diff --git a/lib/auth/storage/storage.go b/lib/auth/storage/storage.go index 9596f12e1e645..76db71182e982 100644 --- a/lib/auth/storage/storage.go +++ b/lib/auth/storage/storage.go @@ -63,7 +63,7 @@ type stateBackend interface { // exists, updates it otherwise) Put(ctx context.Context, i backend.Item) (*backend.Lease, error) // Get returns a single item or not found error - Get(ctx context.Context, key []byte) (*backend.Item, error) + Get(ctx context.Context, key backend.Key) (*backend.Item, error) } // ProcessStorage is a backend for local process state, diff --git a/lib/backend/backend.go b/lib/backend/backend.go index 1cac249ea0510..e3dc116a05f5a 100644 --- a/lib/backend/backend.go +++ b/lib/backend/backend.go @@ -60,17 +60,17 @@ type Backend interface { Update(ctx context.Context, i Item) (*Lease, error) // Get returns a single item or not found error - Get(ctx context.Context, key []byte) (*Item, error) + Get(ctx context.Context, key Key) (*Item, error) // GetRange returns query range - GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*GetResult, error) + GetRange(ctx context.Context, startKey, endKey Key, limit int) (*GetResult, error) // Delete deletes item by key, returns NotFound error // if item does not exist - Delete(ctx context.Context, key []byte) error + Delete(ctx context.Context, key Key) error // DeleteRange deletes range of items with keys between startKey and endKey - DeleteRange(ctx context.Context, startKey, endKey []byte) error + DeleteRange(ctx context.Context, startKey, endKey Key) error // KeepAlive keeps object from expiring, updates lease on the existing object, // expires contains the new expiry to set on the lease, @@ -93,7 +93,7 @@ type Backend interface { } // IterateRange is a helper for stepping over a range -func IterateRange(ctx context.Context, bk Backend, startKey []byte, endKey []byte, limit int, fn func([]Item) (stop bool, err error)) error { +func IterateRange(ctx context.Context, bk Backend, startKey, endKey Key, limit int, fn func([]Item) (stop bool, err error)) error { if limit == 0 || limit > 10_000 { limit = 10_000 } @@ -130,7 +130,7 @@ func IterateRange(ctx context.Context, bk Backend, startKey []byte, endKey []byt // // 2. allow individual backends to expose custom streaming methods s.t. the most performant // impl for a given backend may be used. -func StreamRange(ctx context.Context, bk Backend, startKey, endKey []byte, pageSize int) stream.Stream[Item] { +func StreamRange(ctx context.Context, bk Backend, startKey, endKey Key, pageSize int) stream.Stream[Item] { return stream.PageFunc[Item](func() ([]Item, error) { if startKey == nil { return nil, io.EOF @@ -167,7 +167,7 @@ type Batch interface { // err = backend.KeepAlive(ctx, lease, expires) type Lease struct { // Key is an object representing lease - Key []byte + Key Key // ID is a lease ID, could be empty // Deprecated: use Revision instead ID int64 @@ -187,7 +187,7 @@ type Watch struct { Name string // Prefixes specifies prefixes to watch, // passed to the backend implementation - Prefixes [][]byte + Prefixes []Key // QueueSize is an optional queue size QueueSize int // MetricComponent if set will start reporting @@ -231,7 +231,7 @@ type Event struct { // Item is a key value item type Item struct { // Key is a key of the key value item - Key []byte + Key Key // Value is a value of the key value item Value []byte // Expires is an optional record expiry time @@ -287,7 +287,7 @@ const NoLimit = 0 // nextKey returns the next possible key. // If used with a key prefix, this will return // the end of the range for that key prefix. -func nextKey(key []byte) []byte { +func nextKey(key Key) Key { end := make([]byte, len(key)) copy(end, key) for i := len(end) - 1; i >= 0; i-- { @@ -301,10 +301,10 @@ func nextKey(key []byte) []byte { return noEnd } -var noEnd = []byte{0} +var noEnd = Key{0} // RangeEnd returns end of the range for given key. -func RangeEnd(key []byte) []byte { +func RangeEnd(key Key) Key { return nextKey(key) } @@ -325,7 +325,7 @@ type KeyedItem interface { // have the HostID part. func NextPaginationKey(ki KeyedItem) string { key := GetPaginationKey(ki) - return string(nextKey([]byte(key))) + return string(nextKey(Key(key))) } // GetPaginationKey returns the pagination key given item. @@ -341,13 +341,13 @@ func GetPaginationKey(ki KeyedItem) string { // MaskKeyName masks the given key name. // e.g "123456789" -> "******789" -func MaskKeyName(keyName string) []byte { +func MaskKeyName(keyName string) string { maskedBytes := []byte(keyName) hiddenBefore := int(0.75 * float64(len(keyName))) for i := 0; i < hiddenBefore; i++ { maskedBytes[i] = '*' } - return maskedBytes + return string(maskedBytes) } // Items is a sortable list of backend items @@ -421,7 +421,7 @@ const Separator = '/' // NewKey joins parts into path separated by Separator, // makes sure path always starts with Separator ("/") -func NewKey(parts ...string) []byte { +func NewKey(parts ...string) Key { return internalKey("", parts...) } @@ -429,10 +429,10 @@ func NewKey(parts ...string) []byte { // path of Key. This is to ensure range matching of a path will only // math child paths and not other paths that have the resulting path // as a prefix. -func ExactKey(parts ...string) []byte { +func ExactKey(parts ...string) Key { return append(NewKey(parts...), Separator) } -func internalKey(internalPrefix string, parts ...string) []byte { - return []byte(strings.Join(append([]string{internalPrefix}, parts...), string(Separator))) +func internalKey(internalPrefix string, parts ...string) Key { + return Key(strings.Join(append([]string{internalPrefix}, parts...), string(Separator))) } diff --git a/lib/backend/buffer.go b/lib/backend/buffer.go index 7456ce300a43d..98d8ce262011b 100644 --- a/lib/backend/buffer.go +++ b/lib/backend/buffer.go @@ -217,7 +217,7 @@ func (c *CircularBuffer) fanOutEvent(r Event) { } } -func removeRedundantPrefixes(prefixes [][]byte) [][]byte { +func removeRedundantPrefixes(prefixes []Key) []Key { if len(prefixes) == 0 { return prefixes } diff --git a/lib/backend/buffer_test.go b/lib/backend/buffer_test.go index bb4b89cd181af..cea117b025406 100644 --- a/lib/backend/buffer_test.go +++ b/lib/backend/buffer_test.go @@ -18,6 +18,7 @@ package backend import ( "context" + "fmt" "testing" "time" @@ -48,17 +49,17 @@ func TestWatcherSimple(t *testing.T) { t.Fatalf("Timeout waiting for event.") } - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: 1}}) + b.Emit(Event{Item: Item{Key: Key("/1")}}) select { case e := <-w.Events(): - require.Equal(t, e.Item.ID, int64(1)) + require.Equal(t, Key("/1"), e.Item.Key) case <-time.After(100 * time.Millisecond): t.Fatalf("Timeout waiting for event.") } b.Close() - b.Emit(Event{Item: Item{ID: 2}}) + b.Emit(Event{Item: Item{Key: Key("/2")}}) select { case <-w.Done(): @@ -101,12 +102,12 @@ func TestWatcherCapacity(t *testing.T) { // emit and then consume 10 events. this is much larger than our queue size, // but should succeed since we consume within our grace period. for i := 0; i < 10; i++ { - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: int64(i + 1)}}) + b.Emit(Event{Item: Item{Key: Key(fmt.Sprintf("/%d", i+1))}}) } for i := 0; i < 10; i++ { select { case e := <-w.Events(): - require.Equal(t, e.Item.ID, int64(i+1)) + require.Equal(t, fmt.Sprintf("/%d", i+1), string(e.Item.Key)) default: t.Fatalf("Expected events to be immediately available") } @@ -116,7 +117,7 @@ func TestWatcherCapacity(t *testing.T) { clock.Advance(gracePeriod + time.Second) // emit another event, which will cause buffer to reevaluate the grace period. - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: int64(11)}}) + b.Emit(Event{Item: Item{Key: Key("/11")}}) // ensure that buffer did not close watcher, since previously created backlog // was drained within grace period. @@ -128,13 +129,13 @@ func TestWatcherCapacity(t *testing.T) { // create backlog again, and this time advance past grace period without draining it. for i := 0; i < 10; i++ { - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: int64(i + 12)}}) + b.Emit(Event{Item: Item{Key: Key(fmt.Sprintf("/%d", i+12))}}) } clock.Advance(gracePeriod + time.Second) // emit another event, which will cause buffer to realize that watcher is past // its grace period. - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: int64(22)}}) + b.Emit(Event{Item: Item{Key: Key("/22")}}) select { case <-w.Done(): @@ -174,7 +175,7 @@ func TestWatcherCreationGracePeriod(t *testing.T) { // emit enough events to create a backlog for i := 0; i < queueSize*2; i++ { - b.Emit(Event{Item: Item{Key: []byte{Separator}}}) + b.Emit(Event{Item: Item{Key: Key{Separator}}}) } select { @@ -189,7 +190,7 @@ func TestWatcherCreationGracePeriod(t *testing.T) { // advance well past the backlog grace period, but not past the creation grace period clock.Advance(backlogGracePeriod * 2) - b.Emit(Event{Item: Item{Key: []byte{Separator}}}) + b.Emit(Event{Item: Item{Key: Key{Separator}}}) select { case <-w.Done(): @@ -200,7 +201,7 @@ func TestWatcherCreationGracePeriod(t *testing.T) { // advance well past creation grace period clock.Advance(creationGracePeriod) - b.Emit(Event{Item: Item{Key: []byte{Separator}}}) + b.Emit(Event{Item: Item{Key: Key{Separator}}}) select { case <-w.Done(): default: @@ -236,29 +237,29 @@ func TestWatcherClose(t *testing.T) { // TestRemoveRedundantPrefixes removes redundant prefixes func TestRemoveRedundantPrefixes(t *testing.T) { type tc struct { - in [][]byte - out [][]byte + in []Key + out []Key } tcs := []tc{ { - in: [][]byte{}, - out: [][]byte{}, + in: []Key{}, + out: []Key{}, }, { - in: [][]byte{[]byte("/a")}, - out: [][]byte{[]byte("/a")}, + in: []Key{Key("/a")}, + out: []Key{Key("/a")}, }, { - in: [][]byte{[]byte("/a"), []byte("/")}, - out: [][]byte{[]byte("/")}, + in: []Key{Key("/a"), Key("/")}, + out: []Key{Key("/")}, }, { - in: [][]byte{[]byte("/b"), []byte("/a")}, - out: [][]byte{[]byte("/a"), []byte("/b")}, + in: []Key{Key("/b"), Key("/a")}, + out: []Key{Key("/a"), Key("/b")}, }, { - in: [][]byte{[]byte("/a/b"), []byte("/a"), []byte("/a/b/c"), []byte("/d")}, - out: [][]byte{[]byte("/a"), []byte("/d")}, + in: []Key{Key("/a/b"), Key("/a"), Key("/a/b/c"), Key("/d")}, + out: []Key{Key("/a"), Key("/d")}, }, } for _, tc := range tcs { @@ -276,7 +277,7 @@ func TestWatcherMulti(t *testing.T) { defer b.Close() b.SetInit() - w, err := b.NewWatcher(ctx, Watch{Prefixes: [][]byte{[]byte("/a"), []byte("/a/b")}}) + w, err := b.NewWatcher(ctx, Watch{Prefixes: []Key{Key("/a"), Key("/a/b")}}) require.NoError(t, err) defer w.Close() @@ -287,11 +288,11 @@ func TestWatcherMulti(t *testing.T) { t.Fatalf("Timeout waiting for event.") } - b.Emit(Event{Item: Item{Key: []byte("/a/b/c"), ID: 1}}) + b.Emit(Event{Item: Item{Key: Key("/a/b/c")}}) select { case e := <-w.Events(): - require.Equal(t, e.Item.ID, int64(1)) + require.Equal(t, Key("/a/b/c"), e.Item.Key) case <-time.After(100 * time.Millisecond): t.Fatalf("Timeout waiting for event.") } @@ -320,7 +321,7 @@ func TestWatcherReset(t *testing.T) { t.Fatalf("Timeout waiting for event.") } - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: 1}}) + b.Emit(Event{Item: Item{Key: Key("/1")}}) b.Clear() // make sure watcher has been closed @@ -341,11 +342,11 @@ func TestWatcherReset(t *testing.T) { t.Fatalf("Timeout waiting for event.") } - b.Emit(Event{Item: Item{Key: []byte{Separator}, ID: 2}}) + b.Emit(Event{Item: Item{Key: Key("/2")}}) select { case e := <-w2.Events(): - require.Equal(t, e.Item.ID, int64(2)) + require.Equal(t, Key("/2"), e.Item.Key) case <-time.After(100 * time.Millisecond): t.Fatalf("Timeout waiting for event.") } @@ -356,10 +357,10 @@ func TestWatcherTree(t *testing.T) { wt := newWatcherTree() require.Equal(t, wt.rm(nil), false) - w1 := &BufferWatcher{Watch: Watch{Prefixes: [][]byte{[]byte("/a"), []byte("/a/a1"), []byte("/c")}}} - require.Equal(t, wt.rm(w1), false) + w1 := &BufferWatcher{Watch: Watch{Prefixes: []Key{Key("/a"), Key("/a/a1"), Key("/c")}}} + require.False(t, wt.rm(w1)) - w2 := &BufferWatcher{Watch: Watch{Prefixes: [][]byte{[]byte("/a")}}} + w2 := &BufferWatcher{Watch: Watch{Prefixes: []Key{Key("/a")}}} wt.add(w1) wt.add(w2) diff --git a/lib/backend/dynamo/dynamodbbk.go b/lib/backend/dynamo/dynamodbbk.go index f8d2aa3742b75..4aba248313395 100644 --- a/lib/backend/dynamo/dynamodbbk.go +++ b/lib/backend/dynamo/dynamodbbk.go @@ -381,7 +381,7 @@ func (b *Backend) Update(ctx context.Context, item backend.Item) (*backend.Lease } // GetRange returns range of elements -func (b *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*backend.GetResult, error) { +func (b *Backend) GetRange(ctx context.Context, startKey, endKey backend.Key, limit int) (*backend.GetResult, error) { if len(startKey) == 0 { return nil, trace.BadParameter("missing parameter startKey") } @@ -410,7 +410,7 @@ func (b *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, return &backend.GetResult{Items: values}, nil } -func (b *Backend) getAllRecords(ctx context.Context, startKey []byte, endKey []byte, limit int) (*getResult, error) { +func (b *Backend) getAllRecords(ctx context.Context, startKey, endKey backend.Key, limit int) (*getResult, error) { var result getResult // this code is being extra careful here not to introduce endless loop @@ -444,7 +444,7 @@ const ( ) // DeleteRange deletes range of items with keys between startKey and endKey -func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey []byte) error { +func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey backend.Key) error { if len(startKey) == 0 { return trace.BadParameter("missing parameter startKey") } @@ -491,7 +491,7 @@ func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey []byte) erro } // Get returns a single item or not found error -func (b *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (b *Backend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { r, err := b.getKey(ctx, key) if err != nil { return nil, err @@ -560,7 +560,7 @@ func (b *Backend) CompareAndSwap(ctx context.Context, expected backend.Item, rep } // Delete deletes item by key -func (b *Backend) Delete(ctx context.Context, key []byte) error { +func (b *Backend) Delete(ctx context.Context, key backend.Key) error { if len(key) == 0 { return trace.BadParameter("missing parameter key") } @@ -837,13 +837,13 @@ const ( // prependPrefix adds leading 'teleport/' to the key for backwards compatibility // with previous implementation of DynamoDB backend -func prependPrefix(key []byte) string { +func prependPrefix(key backend.Key) string { return keyPrefix + string(key) } // trimPrefix removes leading 'teleport' from the key -func trimPrefix(key string) []byte { - return []byte(strings.TrimPrefix(key, keyPrefix)) +func trimPrefix(key string) backend.Key { + return backend.Key(strings.TrimPrefix(key, keyPrefix)) } // create helper creates a new key/value pair in Dynamo with a given expiration @@ -884,7 +884,7 @@ func (b *Backend) create(ctx context.Context, item backend.Item, mode int) error return nil } -func (b *Backend) deleteKey(ctx context.Context, key []byte) error { +func (b *Backend) deleteKey(ctx context.Context, key backend.Key) error { av, err := dynamodbattribute.MarshalMap(keyLookup{ HashKey: hashKey, FullPath: prependPrefix(key), @@ -899,7 +899,7 @@ func (b *Backend) deleteKey(ctx context.Context, key []byte) error { return nil } -func (b *Backend) deleteKeyIfExpired(ctx context.Context, key []byte) error { +func (b *Backend) deleteKeyIfExpired(ctx context.Context, key backend.Key) error { _, err := b.svc.DeleteItemWithContext(ctx, &dynamodb.DeleteItemInput{ TableName: aws.String(b.TableName), Key: keyToAttributeValueMap(key), @@ -915,7 +915,7 @@ func (b *Backend) deleteKeyIfExpired(ctx context.Context, key []byte) error { return trace.Wrap(err) } -func (b *Backend) getKey(ctx context.Context, key []byte) (*record, error) { +func (b *Backend) getKey(ctx context.Context, key backend.Key) (*record, error) { av, err := dynamodbattribute.MarshalMap(keyLookup{ HashKey: hashKey, FullPath: prependPrefix(key), @@ -1001,7 +1001,7 @@ func fullPathToAttributeValueMap(fullPath string) map[string]*dynamodb.Attribute } } -func keyToAttributeValueMap(key []byte) map[string]*dynamodb.AttributeValue { +func keyToAttributeValueMap(key backend.Key) map[string]*dynamodb.AttributeValue { return fullPathToAttributeValueMap(prependPrefix(key)) } diff --git a/lib/backend/etcdbk/etcd.go b/lib/backend/etcdbk/etcd.go index 205736f7d4466..64a32295c1443 100644 --- a/lib/backend/etcdbk/etcd.go +++ b/lib/backend/etcdbk/etcd.go @@ -642,7 +642,7 @@ func (b *EtcdBackend) NewWatcher(ctx context.Context, watch backend.Watch) (back } // GetRange returns query range -func (b *EtcdBackend) GetRange(ctx context.Context, startKey, endKey []byte, limit int) (*backend.GetResult, error) { +func (b *EtcdBackend) GetRange(ctx context.Context, startKey, endKey backend.Key, limit int) (*backend.GetResult, error) { if len(startKey) == 0 { return nil, trace.BadParameter("missing parameter startKey") } @@ -818,7 +818,7 @@ func (b *EtcdBackend) KeepAlive(ctx context.Context, lease backend.Lease, expire } // Get returns a single item or not found error -func (b *EtcdBackend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (b *EtcdBackend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { re, err := b.clients.Next().Get(ctx, b.prependPrefix(key)) if err != nil { return nil, convertErr(err) @@ -835,7 +835,7 @@ func (b *EtcdBackend) Get(ctx context.Context, key []byte) (*backend.Item, error } // Delete deletes item by key -func (b *EtcdBackend) Delete(ctx context.Context, key []byte) error { +func (b *EtcdBackend) Delete(ctx context.Context, key backend.Key) error { start := b.clock.Now() re, err := b.clients.Next().Delete(ctx, b.prependPrefix(key)) writeLatencies.Observe(time.Since(start).Seconds()) @@ -851,7 +851,7 @@ func (b *EtcdBackend) Delete(ctx context.Context, key []byte) error { } // DeleteRange deletes range of items with keys between startKey and endKey -func (b *EtcdBackend) DeleteRange(ctx context.Context, startKey, endKey []byte) error { +func (b *EtcdBackend) DeleteRange(ctx context.Context, startKey, endKey backend.Key) error { if len(startKey) == 0 { return trace.BadParameter("missing parameter startKey") } @@ -1018,10 +1018,10 @@ func fromType(eventType mvccpb.Event_EventType) types.OpType { } } -func (b *EtcdBackend) trimPrefix(in []byte) []byte { - return bytes.TrimPrefix(in, []byte(b.cfg.Key)) +func (b *EtcdBackend) trimPrefix(in backend.Key) backend.Key { + return bytes.TrimPrefix(in, backend.Key(b.cfg.Key)) } -func (b *EtcdBackend) prependPrefix(in []byte) string { +func (b *EtcdBackend) prependPrefix(in backend.Key) string { return b.cfg.Key + string(in) } diff --git a/lib/backend/etcdbk/etcd_test.go b/lib/backend/etcdbk/etcd_test.go index 8c4c1d396f36c..df1f76f1326ef 100644 --- a/lib/backend/etcdbk/etcd_test.go +++ b/lib/backend/etcdbk/etcd_test.go @@ -116,7 +116,7 @@ func TestPrefix(t *testing.T) { // When I push an item with a key starting with "/" into etcd via the // _prefixed_ client... item := backend.Item{ - Key: []byte("/foo"), + Key: backend.Key("/foo"), Value: []byte("bar"), } _, err = prefixedUut.Put(ctx, item) @@ -134,7 +134,7 @@ func TestPrefix(t *testing.T) { // When I push an item with a key that does _not_ start with a separator // char (i.e. "/") into etcd via the _prefixed_ client... item = backend.Item{ - Key: []byte("foo"), + Key: backend.Key("foo"), Value: []byte("bar"), } _, err = prefixedUut.Put(ctx, item) diff --git a/lib/backend/firestore/firestorebk.go b/lib/backend/firestore/firestorebk.go index e20bcb0654738..a2417ee011cc3 100644 --- a/lib/backend/firestore/firestorebk.go +++ b/lib/backend/firestore/firestorebk.go @@ -107,11 +107,11 @@ type Backend struct { } type record struct { - Key []byte `firestore:"key,omitempty"` - Timestamp int64 `firestore:"timestamp,omitempty"` - Expires int64 `firestore:"expires,omitempty"` - ID int64 `firestore:"id,omitempty"` - Value []byte `firestore:"value,omitempty"` + Key backend.Key `firestore:"key,omitempty"` + Timestamp int64 `firestore:"timestamp,omitempty"` + Expires int64 `firestore:"expires,omitempty"` + ID int64 `firestore:"id,omitempty"` + Value []byte `firestore:"value,omitempty"` } // legacyRecord is an older version of record used to marshal backend.Items. @@ -154,7 +154,7 @@ func newRecordFromDoc(doc *firestore.DocumentSnapshot) (*record, error) { return nil, ConvertGRPCError(err) } r = record{ - Key: []byte(rl.Key), + Key: backend.Key(rl.Key), Value: []byte(rl.Value), Timestamp: rl.Timestamp, Expires: rl.Expires, @@ -382,7 +382,7 @@ func (b *Backend) Update(ctx context.Context, item backend.Item) (*backend.Lease return b.newLease(item), nil } -func (b *Backend) getRangeDocs(ctx context.Context, startKey []byte, endKey []byte, limit int) ([]*firestore.DocumentSnapshot, error) { +func (b *Backend) getRangeDocs(ctx context.Context, startKey, endKey backend.Key, limit int) ([]*firestore.DocumentSnapshot, error) { if len(startKey) == 0 { return nil, trace.BadParameter("missing parameter startKey") } @@ -417,7 +417,7 @@ func (b *Backend) getRangeDocs(ctx context.Context, startKey []byte, endKey []by } // GetRange returns range of elements -func (b *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*backend.GetResult, error) { +func (b *Backend) GetRange(ctx context.Context, startKey, endKey backend.Key, limit int) (*backend.GetResult, error) { docSnaps, err := b.getRangeDocs(ctx, startKey, endKey, limit) if err != nil { return nil, trace.Wrap(err) @@ -456,7 +456,7 @@ func (b *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, } // DeleteRange deletes range of items with keys between startKey and endKey -func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey []byte) error { +func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey backend.Key) error { docs, err := b.getRangeDocs(ctx, startKey, endKey, backend.DefaultRangeLimit) if err != nil { return trace.Wrap(err) @@ -466,7 +466,7 @@ func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey []byte) erro } // Get returns a single item or not found error -func (b *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (b *Backend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { if len(key) == 0 { return nil, trace.BadParameter("missing parameter key") } @@ -550,7 +550,7 @@ func (b *Backend) CompareAndSwap(ctx context.Context, expected backend.Item, rep } // Delete deletes item by key -func (b *Backend) Delete(ctx context.Context, key []byte) error { +func (b *Backend) Delete(ctx context.Context, key backend.Key) error { if len(key) == 0 { return trace.BadParameter("missing parameter key") } @@ -638,7 +638,7 @@ func (b *Backend) newLease(item backend.Item) *backend.Lease { // IDs. See // https://firebase.google.com/docs/firestore/quotas#collections_documents_and_fields // for Firestore limitations. -func (b *Backend) keyToDocumentID(key []byte) string { +func (b *Backend) keyToDocumentID(key backend.Key) string { // URL-safe base64 will not have periods or forward slashes. // This should satisfy the Firestore requirements. return base64.URLEncoding.EncodeToString(key) diff --git a/lib/backend/helpers.go b/lib/backend/helpers.go index 64386e2581a48..f9eae94437032 100644 --- a/lib/backend/helpers.go +++ b/lib/backend/helpers.go @@ -27,20 +27,15 @@ import ( ) const ( - flagsPrefix = ".flags" locksPrefix = ".locks" ) -func FlagKey(parts ...string) []byte { - return internalKey(flagsPrefix, parts...) -} - -func lockKey(parts ...string) []byte { +func lockKey(parts ...string) Key { return internalKey(locksPrefix, parts...) } type Lock struct { - key []byte + key Key id []byte ttl time.Duration } diff --git a/lib/backend/key.go b/lib/backend/key.go new file mode 100644 index 0000000000000..2ff85090ef9fd --- /dev/null +++ b/lib/backend/key.go @@ -0,0 +1,20 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package backend + +// Key is the unique identifier for an [Item]. +type Key = []byte diff --git a/lib/backend/kubernetes/kubernetes.go b/lib/backend/kubernetes/kubernetes.go index 04b44ae46f071..40fafcd2f584f 100644 --- a/lib/backend/kubernetes/kubernetes.go +++ b/lib/backend/kubernetes/kubernetes.go @@ -219,7 +219,7 @@ func (b *Backend) Exists(ctx context.Context) bool { // Get reads the secret and extracts the key from it. // If the secret does not exist or the key is not found it returns trace.Notfound, // otherwise returns the underlying error. -func (b *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (b *Backend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { b.mu.Lock() defer b.mu.Unlock() @@ -258,7 +258,7 @@ func (b *Backend) getSecret(ctx context.Context) (*corev1.Secret, error) { // readSecretData reads the secret content and extracts the content for key. // returns an error if the key does not exist or the data is empty. -func (b *Backend) readSecretData(ctx context.Context, key []byte) (*backend.Item, error) { +func (b *Backend) readSecretData(ctx context.Context, key backend.Key) (*backend.Item, error) { secret, err := b.getSecret(ctx) if err != nil { return nil, trace.Wrap(err) @@ -350,7 +350,7 @@ func generateSecretAnnotations(namespace, releaseNameEnv string) map[string]stri // backendKeyToSecret replaces the "/" with "." // "/" chars are not allowed in Kubernetes Secret keys. -func backendKeyToSecret(k []byte) string { +func backendKeyToSecret(k backend.Key) string { return strings.ReplaceAll(string(k), "/", ".") } diff --git a/lib/backend/kubernetes/kubernetes_test.go b/lib/backend/kubernetes/kubernetes_test.go index cc04c8f7a7fb6..2a7cb055fac6a 100644 --- a/lib/backend/kubernetes/kubernetes_test.go +++ b/lib/backend/kubernetes/kubernetes_test.go @@ -140,7 +140,7 @@ func TestBackend_Get(t *testing.T) { } type args struct { - key []byte + key backend.Key } tests := []struct { diff --git a/lib/backend/lite/lite.go b/lib/backend/lite/lite.go index b578da5f24ba2..6b66d4b0544db 100644 --- a/lib/backend/lite/lite.go +++ b/lib/backend/lite/lite.go @@ -682,7 +682,7 @@ func (l *Backend) Update(ctx context.Context, i backend.Item) (*backend.Lease, e } // Get returns a single item or not found error -func (l *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (l *Backend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { if len(key) == 0 { return nil, trace.BadParameter("missing parameter key") } @@ -697,7 +697,7 @@ func (l *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { } // getInTransaction returns an item, works in transaction -func (l *Backend) getInTransaction(ctx context.Context, key []byte, tx *sql.Tx, item *backend.Item) error { +func (l *Backend) getInTransaction(ctx context.Context, key backend.Key, tx *sql.Tx, item *backend.Item) error { // When in mirror mode, don't set the current time so the SELECT query // returns expired items. var now time.Time @@ -725,7 +725,7 @@ func (l *Backend) getInTransaction(ctx context.Context, key []byte, tx *sql.Tx, } // GetRange returns query range -func (l *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*backend.GetResult, error) { +func (l *Backend) GetRange(ctx context.Context, startKey, endKey backend.Key, limit int) (*backend.GetResult, error) { if len(startKey) == 0 { return nil, trace.BadParameter("missing parameter startKey") } @@ -823,7 +823,7 @@ func (l *Backend) KeepAlive(ctx context.Context, lease backend.Lease, expires ti }) } -func (l *Backend) deleteInTransaction(ctx context.Context, key []byte, tx *sql.Tx) error { +func (l *Backend) deleteInTransaction(ctx context.Context, key backend.Key, tx *sql.Tx) error { stmt, err := tx.PrepareContext(ctx, "DELETE FROM kv WHERE key = ?") if err != nil { return trace.Wrap(err) @@ -858,7 +858,7 @@ func (l *Backend) deleteInTransaction(ctx context.Context, key []byte, tx *sql.T // Delete deletes item by key, returns NotFound error // if item does not exist -func (l *Backend) Delete(ctx context.Context, key []byte) error { +func (l *Backend) Delete(ctx context.Context, key backend.Key) error { if len(key) == 0 { return trace.BadParameter("missing parameter key") } @@ -869,7 +869,7 @@ func (l *Backend) Delete(ctx context.Context, key []byte) error { // DeleteRange deletes range of items with keys between startKey and endKey // Note that elements deleted by range do not produce any events -func (l *Backend) DeleteRange(ctx context.Context, startKey, endKey []byte) error { +func (l *Backend) DeleteRange(ctx context.Context, startKey, endKey backend.Key) error { if len(startKey) == 0 { return trace.BadParameter("missing parameter startKey") } @@ -889,7 +889,7 @@ func (l *Backend) DeleteRange(ctx context.Context, startKey, endKey []byte) erro return trace.Wrap(err) } defer rows.Close() - var keys [][]byte + var keys []backend.Key for rows.Next() { var key []byte if err := rows.Scan(&key); err != nil { diff --git a/lib/backend/lite/periodic.go b/lib/backend/lite/periodic.go index 6c17502144d25..0b310d49b16a2 100644 --- a/lib/backend/lite/periodic.go +++ b/lib/backend/lite/periodic.go @@ -86,7 +86,7 @@ func (l *Backend) removeExpiredKeys() error { return trace.Wrap(err) } defer rows.Close() - var keys [][]byte + var keys []backend.Key for rows.Next() { var key []byte if err := rows.Scan(&key); err != nil { diff --git a/lib/backend/memory/item.go b/lib/backend/memory/item.go index 95fb5ee1e43fc..9fe9a9262cce8 100644 --- a/lib/backend/memory/item.go +++ b/lib/backend/memory/item.go @@ -48,7 +48,7 @@ func (i *btreeItem) Less(iother btree.Item) bool { // prefixItem is used for prefix matches on a B-Tree type prefixItem struct { // prefix is a prefix to match - prefix []byte + prefix backend.Key } // Less is used for Btree operations diff --git a/lib/backend/memory/memory.go b/lib/backend/memory/memory.go index 152cb038f2d8e..b1db099f8373d 100644 --- a/lib/backend/memory/memory.go +++ b/lib/backend/memory/memory.go @@ -181,7 +181,7 @@ func (m *Memory) Create(ctx context.Context, i backend.Item) (*backend.Lease, er } // Get returns a single item or not found error -func (m *Memory) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (m *Memory) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { if len(key) == 0 { return nil, trace.BadParameter("missing parameter key") } @@ -272,7 +272,7 @@ func (m *Memory) PutRange(ctx context.Context, items []backend.Item) error { // Delete deletes item by key, returns NotFound error // if item does not exist -func (m *Memory) Delete(ctx context.Context, key []byte) error { +func (m *Memory) Delete(ctx context.Context, key backend.Key) error { if len(key) == 0 { return trace.BadParameter("missing parameter key") } @@ -297,7 +297,7 @@ func (m *Memory) Delete(ctx context.Context, key []byte) error { // DeleteRange deletes range of items with keys between startKey and endKey // Note that elements deleted by range do not produce any events -func (m *Memory) DeleteRange(ctx context.Context, startKey, endKey []byte) error { +func (m *Memory) DeleteRange(ctx context.Context, startKey, endKey backend.Key) error { if len(startKey) == 0 { return trace.BadParameter("missing parameter startKey") } @@ -322,7 +322,7 @@ func (m *Memory) DeleteRange(ctx context.Context, startKey, endKey []byte) error } // GetRange returns query range -func (m *Memory) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*backend.GetResult, error) { +func (m *Memory) GetRange(ctx context.Context, startKey, endKey backend.Key, limit int) (*backend.GetResult, error) { if len(startKey) == 0 { return nil, trace.BadParameter("missing parameter startKey") } @@ -416,7 +416,7 @@ func (m *Memory) generateID() int64 { return atomic.AddInt64(&m.nextID, 1) } -func (m *Memory) getRange(ctx context.Context, startKey, endKey []byte, limit int) backend.GetResult { +func (m *Memory) getRange(ctx context.Context, startKey, endKey backend.Key, limit int) backend.GetResult { var res backend.GetResult m.tree.AscendRange(&btreeItem{Item: backend.Item{Key: startKey}}, &btreeItem{Item: backend.Item{Key: endKey}}, func(item *btreeItem) bool { res.Items = append(res.Items, item.Item) diff --git a/lib/backend/pgbk/pgbk.go b/lib/backend/pgbk/pgbk.go index b8ebb9daf17cb..59443880aefd6 100644 --- a/lib/backend/pgbk/pgbk.go +++ b/lib/backend/pgbk/pgbk.go @@ -357,7 +357,7 @@ func (b *Backend) Update(ctx context.Context, i backend.Item) (*backend.Lease, e } // Get implements [backend.Backend]. -func (b *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (b *Backend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { item, err := pgcommon.RetryIdempotent(ctx, b.log, func() (*backend.Item, error) { batch := new(pgx.Batch) // batches run in an implicit transaction @@ -403,7 +403,7 @@ func (b *Backend) Get(ctx context.Context, key []byte) (*backend.Item, error) { } // GetRange implements [backend.Backend]. -func (b *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*backend.GetResult, error) { +func (b *Backend) GetRange(ctx context.Context, startKey, endKey backend.Key, limit int) (*backend.GetResult, error) { if limit <= 0 { limit = backend.DefaultRangeLimit } @@ -454,7 +454,7 @@ func (b *Backend) GetRange(ctx context.Context, startKey []byte, endKey []byte, } // Delete implements [backend.Backend]. -func (b *Backend) Delete(ctx context.Context, key []byte) error { +func (b *Backend) Delete(ctx context.Context, key backend.Key) error { deleted, err := pgcommon.Retry(ctx, b.log, func() (bool, error) { tag, err := b.pool.Exec(ctx, "DELETE FROM kv WHERE kv.key = $1 AND (kv.expires IS NULL OR kv.expires > now())", nonNil(key)) @@ -474,7 +474,7 @@ func (b *Backend) Delete(ctx context.Context, key []byte) error { } // DeleteRange implements [backend.Backend]. -func (b *Backend) DeleteRange(ctx context.Context, startKey []byte, endKey []byte) error { +func (b *Backend) DeleteRange(ctx context.Context, startKey, endKey backend.Key) error { // this is the only backend operation that might affect a disproportionate // amount of rows at the same time; in actual operation, DeleteRange hardly // ever deletes more than dozens of items at once, and logical decoding diff --git a/lib/backend/pgbk/wal2json_test.go b/lib/backend/pgbk/wal2json_test.go index eebbda9caec29..4078784bba4cb 100644 --- a/lib/backend/pgbk/wal2json_test.go +++ b/lib/backend/pgbk/wal2json_test.go @@ -153,7 +153,7 @@ func TestMessage(t *testing.T) { require.Empty(t, cmp.Diff(evs[0], backend.Event{ Type: types.OpPut, Item: backend.Item{ - Key: []byte("foo"), + Key: backend.Key("foo"), Value: []byte(""), ID: idFromRevision(rev), }, @@ -177,7 +177,7 @@ func TestMessage(t *testing.T) { require.Empty(t, cmp.Diff(evs[0], backend.Event{ Type: types.OpPut, Item: backend.Item{ - Key: []byte("foo"), + Key: backend.Key("foo"), Value: []byte("foo2"), ID: idFromRevision(rev), }, @@ -205,13 +205,13 @@ func TestMessage(t *testing.T) { require.Empty(t, cmp.Diff(evs[0], backend.Event{ Type: types.OpDelete, Item: backend.Item{ - Key: []byte("foo"), + Key: backend.Key("foo"), }, })) require.Empty(t, cmp.Diff(evs[1], backend.Event{ Type: types.OpPut, Item: backend.Item{ - Key: []byte("foo2"), + Key: backend.Key("foo2"), Value: []byte("foo2"), Expires: time.Date(2023, 9, 5, 15, 57, 1, 340426000, time.UTC), ID: idFromRevision(rev), @@ -248,7 +248,7 @@ func TestMessage(t *testing.T) { require.Empty(t, cmp.Diff(evs[0], backend.Event{ Type: types.OpDelete, Item: backend.Item{ - Key: []byte("foo"), + Key: backend.Key("foo"), }, })) } diff --git a/lib/backend/report.go b/lib/backend/report.go index b661ecd7b7f51..3585a83581fee 100644 --- a/lib/backend/report.go +++ b/lib/backend/report.go @@ -118,7 +118,7 @@ func (s *Reporter) GetName() string { } // GetRange returns query range -func (s *Reporter) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*GetResult, error) { +func (s *Reporter) GetRange(ctx context.Context, startKey, endKey Key, limit int) (*GetResult, error) { ctx, span := s.Tracer.Start( ctx, "backend/GetRange", @@ -220,7 +220,7 @@ func (s *Reporter) Update(ctx context.Context, i Item) (*Lease, error) { } // Get returns a single item or not found error -func (s *Reporter) Get(ctx context.Context, key []byte) (*Item, error) { +func (s *Reporter) Get(ctx context.Context, key Key) (*Item, error) { ctx, span := s.Tracer.Start( ctx, "backend/Get", @@ -265,7 +265,7 @@ func (s *Reporter) CompareAndSwap(ctx context.Context, expected Item, replaceWit } // Delete deletes item by key -func (s *Reporter) Delete(ctx context.Context, key []byte) error { +func (s *Reporter) Delete(ctx context.Context, key Key) error { ctx, span := s.Tracer.Start( ctx, "backend/Delete", @@ -287,7 +287,7 @@ func (s *Reporter) Delete(ctx context.Context, key []byte) error { } // DeleteRange deletes range of items -func (s *Reporter) DeleteRange(ctx context.Context, startKey []byte, endKey []byte) error { +func (s *Reporter) DeleteRange(ctx context.Context, startKey, endKey Key) error { ctx, span := s.Tracer.Start( ctx, "backend/DeleteRange", @@ -376,7 +376,7 @@ type topRequestsCacheKey struct { } // trackRequests tracks top requests, endKey is supplied for ranges -func (s *Reporter) trackRequest(opType types.OpType, key []byte, endKey []byte) { +func (s *Reporter) trackRequest(opType types.OpType, key Key, endKey Key) { if len(key) == 0 { return } @@ -446,7 +446,7 @@ func buildKeyLabel(key string, sensitivePrefixes, singletonPrefixes []string, is // if the first non-empty segment is a secret range and there are at least two non-empty // segments, then the second non-empty segment should be masked. if finalLen-realStart > 1 && slices.Contains(sensitivePrefixes, parts[realStart]) { - parts[realStart+1] = string(MaskKeyName(parts[realStart+1])) + parts[realStart+1] = MaskKeyName(parts[realStart+1]) } return strings.Join(parts[:finalLen], string(Separator)) diff --git a/lib/backend/sanitize.go b/lib/backend/sanitize.go index c36828b4ca0e4..11cf6c3d649ff 100644 --- a/lib/backend/sanitize.go +++ b/lib/backend/sanitize.go @@ -40,12 +40,12 @@ var denyPatterns = []*regexp.Regexp{ } // isKeySafe checks if the passed in key conforms to whitelist -func isKeySafe(s []byte) bool { +func isKeySafe(s Key) bool { return allowPattern.Match(s) && !denyPatternsMatch(s) && utf8.Valid(s) } // denyPatternsMatch checks if the passed in key conforms to the deny patterns. -func denyPatternsMatch(s []byte) bool { +func denyPatternsMatch(s Key) bool { for _, pattern := range denyPatterns { if pattern.Match(s) { return true @@ -69,7 +69,7 @@ func NewSanitizer(backend Backend) *Sanitizer { } // GetRange returns query range -func (s *Sanitizer) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*GetResult, error) { +func (s *Sanitizer) GetRange(ctx context.Context, startKey, endKey Key, limit int) (*GetResult, error) { if !isKeySafe(startKey) { return nil, trace.BadParameter(errorMessage, startKey) } @@ -104,7 +104,7 @@ func (s *Sanitizer) Update(ctx context.Context, i Item) (*Lease, error) { } // Get returns a single item or not found error -func (s *Sanitizer) Get(ctx context.Context, key []byte) (*Item, error) { +func (s *Sanitizer) Get(ctx context.Context, key Key) (*Item, error) { if !isKeySafe(key) { return nil, trace.BadParameter(errorMessage, key) } @@ -122,7 +122,7 @@ func (s *Sanitizer) CompareAndSwap(ctx context.Context, expected Item, replaceWi } // Delete deletes item by key -func (s *Sanitizer) Delete(ctx context.Context, key []byte) error { +func (s *Sanitizer) Delete(ctx context.Context, key Key) error { if !isKeySafe(key) { return trace.BadParameter(errorMessage, key) } @@ -130,7 +130,7 @@ func (s *Sanitizer) Delete(ctx context.Context, key []byte) error { } // DeleteRange deletes range of items -func (s *Sanitizer) DeleteRange(ctx context.Context, startKey []byte, endKey []byte) error { +func (s *Sanitizer) DeleteRange(ctx context.Context, startKey, endKey Key) error { // we only validate the start key, since we often compute the end key // in order to delete a bunch of related entries if !isKeySafe(startKey) { diff --git a/lib/backend/sanitize_test.go b/lib/backend/sanitize_test.go index dca2b696014be..939e9749f810f 100644 --- a/lib/backend/sanitize_test.go +++ b/lib/backend/sanitize_test.go @@ -142,11 +142,11 @@ func (n *nopBackend) GetName() string { return "nop" } -func (n *nopBackend) Get(_ context.Context, _ []byte) (*Item, error) { +func (n *nopBackend) Get(_ context.Context, _ Key) (*Item, error) { return &Item{}, nil } -func (n *nopBackend) GetRange(_ context.Context, startKey []byte, endKey []byte, limit int) (*GetResult, error) { +func (n *nopBackend) GetRange(_ context.Context, startKey, endKey Key, limit int) (*GetResult, error) { return &GetResult{Items: []Item{ {Key: []byte("foo"), Value: []byte("bar")}, }}, nil @@ -168,7 +168,7 @@ func (n *nopBackend) CompareAndSwap(_ context.Context, _ Item, _ Item) (*Lease, return &Lease{}, nil } -func (n *nopBackend) Delete(_ context.Context, _ []byte) error { +func (n *nopBackend) Delete(_ context.Context, _ Key) error { return nil } diff --git a/lib/backend/test/suite.go b/lib/backend/test/suite.go index b9265eb21b6e2..950e3a025e738 100644 --- a/lib/backend/test/suite.go +++ b/lib/backend/test/suite.go @@ -516,7 +516,7 @@ func testKeepAlive(t *testing.T, newBackend Constructor) { defer cancel() // When I create a new watcher... - watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: [][]byte{prefix("")}}) + watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: []backend.Key{prefix("")}}) require.NoError(t, err) defer func() { require.NoError(t, watcher.Close()) }() @@ -578,7 +578,7 @@ func testEvents(t *testing.T, newBackend Constructor) { defer cancel() // Create a new watcher for the test prefix. - watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: [][]byte{prefix("")}}) + watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: []backend.Key{prefix("")}}) require.NoError(t, err) defer func() { require.NoError(t, watcher.Close()) }() @@ -706,7 +706,7 @@ func testLimit(t *testing.T, newBackend Constructor) { // requireEvent asserts that a given event type with the given key is emitted // by a watcher within the supplied timeout, returning that event for further // inspection if successful. -func requireEvent(t *testing.T, watcher backend.Watcher, eventType types.OpType, key []byte, timeout time.Duration) backend.Event { +func requireEvent(t *testing.T, watcher backend.Watcher, eventType types.OpType, key backend.Key, timeout time.Duration) backend.Event { t.Helper() select { case e := <-watcher.Events(): @@ -755,7 +755,7 @@ func testWatchersClose(t *testing.T, newBackend Constructor) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: [][]byte{prefix("")}}) + watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: []backend.Key{prefix("")}}) require.NoError(t, err) // cancel context -> get watcher to close @@ -768,7 +768,7 @@ func testWatchersClose(t *testing.T, newBackend Constructor) { } // closing backend should close associated watcher too - watcher, err = uut.NewWatcher(context.Background(), backend.Watch{Prefixes: [][]byte{prefix("")}}) + watcher, err = uut.NewWatcher(context.Background(), backend.Watch{Prefixes: []backend.Key{prefix("")}}) require.NoError(t, err) require.NoError(t, uut.Close()) @@ -1026,7 +1026,7 @@ func testMirror(t *testing.T, newBackend Constructor) { defer cancel() // Create a new watcher for the test prefix. - watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: [][]byte{prefix("")}}) + watcher, err := uut.NewWatcher(ctx, backend.Watch{Prefixes: []backend.Key{prefix("")}}) require.NoError(t, err) defer func() { require.NoError(t, watcher.Close()) }() @@ -1092,7 +1092,7 @@ func testMirror(t *testing.T, newBackend Constructor) { require.NoError(t, err) } -func AddItem(ctx context.Context, t *testing.T, uut backend.Backend, key []byte, value string, expires time.Time) (backend.Item, backend.Lease) { +func AddItem(ctx context.Context, t *testing.T, uut backend.Backend, key backend.Key, value string, expires time.Time) (backend.Item, backend.Lease) { t.Helper() item := backend.Item{ Key: key, @@ -1123,9 +1123,9 @@ func requireWaitGroupToFinish(ctx context.Context, t *testing.T, waitGroup *sync // MakePrefix returns function that appends unique prefix // to any key, used to make test suite concurrent-run proof -func MakePrefix() func(k string) []byte { +func MakePrefix() func(k string) backend.Key { id := "/" + uuid.New().String() - return func(k string) []byte { - return []byte(id + k) + return func(k string) backend.Key { + return backend.Key(id + k) } } diff --git a/lib/backend/wrap.go b/lib/backend/wrap.go index 3994229b19f9b..a4d2581911b55 100644 --- a/lib/backend/wrap.go +++ b/lib/backend/wrap.go @@ -62,7 +62,7 @@ func (s *Wrapper) SetReadError(err error) { } // GetRange returns query range -func (s *Wrapper) GetRange(ctx context.Context, startKey []byte, endKey []byte, limit int) (*GetResult, error) { +func (s *Wrapper) GetRange(ctx context.Context, startKey, endKey Key, limit int) (*GetResult, error) { if err := s.GetReadError(); err != nil { return nil, trace.Wrap(err) } @@ -86,7 +86,7 @@ func (s *Wrapper) Update(ctx context.Context, i Item) (*Lease, error) { } // Get returns a single item or not found error -func (s *Wrapper) Get(ctx context.Context, key []byte) (*Item, error) { +func (s *Wrapper) Get(ctx context.Context, key Key) (*Item, error) { if err := s.GetReadError(); err != nil { return nil, trace.Wrap(err) } @@ -100,12 +100,12 @@ func (s *Wrapper) CompareAndSwap(ctx context.Context, expected Item, replaceWith } // Delete deletes item by key -func (s *Wrapper) Delete(ctx context.Context, key []byte) error { +func (s *Wrapper) Delete(ctx context.Context, key Key) error { return s.backend.Delete(ctx, key) } // DeleteRange deletes range of items -func (s *Wrapper) DeleteRange(ctx context.Context, startKey []byte, endKey []byte) error { +func (s *Wrapper) DeleteRange(ctx context.Context, startKey, endKey Key) error { return s.backend.DeleteRange(ctx, startKey, endKey) } diff --git a/lib/service/service.go b/lib/service/service.go index 6b3b56f290803..2de84fb9d67af 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -6134,7 +6134,7 @@ type kubernetesBackend interface { // exists, updates it otherwise) Put(ctx context.Context, i backend.Item) (*backend.Lease, error) // Get returns a single item or not found error - Get(ctx context.Context, key []byte) (*backend.Item, error) + Get(ctx context.Context, key backend.Key) (*backend.Item, error) } // readHostIDFromStorages tries to read the `host_uuid` value from different storages, diff --git a/lib/service/service_test.go b/lib/service/service_test.go index a3ba37f2a23dc..2e366f90f3051 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -1195,7 +1195,7 @@ func (f *fakeKubeBackend) Put(ctx context.Context, i backend.Item) (*backend.Lea } // Get returns a single item or not found error -func (f *fakeKubeBackend) Get(ctx context.Context, key []byte) (*backend.Item, error) { +func (f *fakeKubeBackend) Get(ctx context.Context, key backend.Key) (*backend.Item, error) { return f.getData, f.getErr } diff --git a/lib/services/local/dynamic_access.go b/lib/services/local/dynamic_access.go index 494b6a30c68b8..4b12be98608a8 100644 --- a/lib/services/local/dynamic_access.go +++ b/lib/services/local/dynamic_access.go @@ -485,11 +485,11 @@ func itemToAccessRequest(item backend.Item, opts ...services.MarshalOption) (*ty return req, nil } -func accessRequestKey(name string) []byte { +func accessRequestKey(name string) backend.Key { return backend.NewKey(accessRequestsPrefix, name, paramsPrefix) } -func AccessRequestAllowedPromotionKey(name string) []byte { +func AccessRequestAllowedPromotionKey(name string) backend.Key { return backend.NewKey(accessRequestPromotionPrefix, name, paramsPrefix) } diff --git a/lib/services/local/events.go b/lib/services/local/events.go index 4e93345cc5feb..7d12267df3d0d 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -57,7 +57,7 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch types.Watch) (type validKinds := make([]types.WatchKind, 0, len(watch.Kinds)) var parsers []resourceParser - var prefixes [][]byte + var prefixes []backend.Key for _, kind := range watch.Kinds { if kind.Name != "" && kind.Kind != types.KindNamespace { if watch.AllowPartialSuccess { @@ -318,26 +318,26 @@ type resourceParser interface { // parse parses resource from the backend event parse(event backend.Event) (types.Resource, error) // match returns true if event key matches - match(key []byte) bool + match(key backend.Key) bool // prefixes returns prefixes to watch - prefixes() [][]byte + prefixes() []backend.Key } // baseParser is a partial implementation of resourceParser for the most common // resource types (stored under a static prefix). type baseParser struct { - matchPrefixes [][]byte + matchPrefixes []backend.Key } -func newBaseParser(prefixes ...[]byte) baseParser { +func newBaseParser(prefixes ...backend.Key) baseParser { return baseParser{matchPrefixes: prefixes} } -func (p baseParser) prefixes() [][]byte { +func (p baseParser) prefixes() []backend.Key { return p.matchPrefixes } -func (p baseParser) match(key []byte) bool { +func (p baseParser) match(key backend.Key) bool { for _, prefix := range p.matchPrefixes { if bytes.HasPrefix(key, prefix) { return true @@ -682,7 +682,7 @@ type namespaceParser struct { baseParser } -func (p *namespaceParser) match(key []byte) bool { +func (p *namespaceParser) match(key backend.Key) bool { // namespaces are stored under key '/namespaces//params' // and this code matches similar pattern return p.baseParser.match(key) && @@ -752,15 +752,15 @@ func newAccessRequestParser(m map[string]string) (*accessRequestParser, error) { type accessRequestParser struct { filter types.AccessRequestFilter - matchPrefix []byte - matchSuffix []byte + matchPrefix backend.Key + matchSuffix backend.Key } -func (p *accessRequestParser) prefixes() [][]byte { - return [][]byte{p.matchPrefix} +func (p *accessRequestParser) prefixes() []backend.Key { + return []backend.Key{p.matchPrefix} } -func (p *accessRequestParser) match(key []byte) bool { +func (p *accessRequestParser) match(key backend.Key) bool { if !bytes.HasPrefix(key, p.matchPrefix) { return false } @@ -798,7 +798,7 @@ type userParser struct { baseParser } -func (p *userParser) match(key []byte) bool { +func (p *userParser) match(key backend.Key) bool { // users are stored under key '/web/users//params' // and this code matches similar pattern return p.baseParser.match(key) && @@ -1283,14 +1283,14 @@ func newRemoteClusterParser() *remoteClusterParser { } type remoteClusterParser struct { - matchPrefix []byte + matchPrefix backend.Key } -func (p *remoteClusterParser) prefixes() [][]byte { - return [][]byte{p.matchPrefix} +func (p *remoteClusterParser) prefixes() []backend.Key { + return []backend.Key{p.matchPrefix} } -func (p *remoteClusterParser) match(key []byte) bool { +func (p *remoteClusterParser) match(key backend.Key) bool { return bytes.HasPrefix(key, p.matchPrefix) } @@ -1346,14 +1346,14 @@ func newNetworkRestrictionsParser() *networkRestrictionsParser { } type networkRestrictionsParser struct { - matchPrefix []byte + matchPrefix backend.Key } -func (p *networkRestrictionsParser) prefixes() [][]byte { - return [][]byte{p.matchPrefix} +func (p *networkRestrictionsParser) prefixes() []backend.Key { + return []backend.Key{p.matchPrefix} } -func (p *networkRestrictionsParser) match(key []byte) bool { +func (p *networkRestrictionsParser) match(key backend.Key) bool { return bytes.HasPrefix(key, p.matchPrefix) } @@ -2055,7 +2055,7 @@ type EventMatcher interface { // base returns last element delimited by separator, index is // is an index of the key part to get counting from the end -func base(key []byte, offset int) ([]byte, error) { +func base(key backend.Key, offset int) ([]byte, error) { parts := bytes.Split(key, []byte{backend.Separator}) if len(parts) < offset+1 { return nil, trace.NotFound("failed parsing %v", string(key)) @@ -2064,7 +2064,7 @@ func base(key []byte, offset int) ([]byte, error) { } // baseTwoKeys returns two last keys -func baseTwoKeys(key []byte) (string, string, error) { +func baseTwoKeys(key backend.Key) (string, string, error) { parts := bytes.Split(key, []byte{backend.Separator}) if len(parts) < 2 { return "", "", trace.NotFound("failed parsing %v", string(key)) diff --git a/lib/services/local/externalauditstorage.go b/lib/services/local/externalauditstorage.go index 954c730e43d74..f42e0ec33fca8 100644 --- a/lib/services/local/externalauditstorage.go +++ b/lib/services/local/externalauditstorage.go @@ -241,7 +241,7 @@ func (s *ExternalAuditStorageService) DisableClusterExternalAuditStorage(ctx con // checkAWSIntegration checks that [integrationName] names an AWS OIDC integration that currently exists, and // returns the backend key and revision if the AWS OIDC integration. -func (s *ExternalAuditStorageService) checkAWSIntegration(ctx context.Context, integrationName string) (key []byte, revision string, err error) { +func (s *ExternalAuditStorageService) checkAWSIntegration(ctx context.Context, integrationName string) (key backend.Key, revision string, err error) { integrationsSvc, err := NewIntegrationsService(s.backend) if err != nil { return nil, "", trace.Wrap(err) @@ -256,7 +256,7 @@ func (s *ExternalAuditStorageService) checkAWSIntegration(ctx context.Context, i return integrationsSvc.svc.MakeKey(integrationName), integration.GetRevision(), nil } -func getExternalAuditStorage(ctx context.Context, bk backend.Backend, key []byte) (*externalauditstorage.ExternalAuditStorage, error) { +func getExternalAuditStorage(ctx context.Context, bk backend.Backend, key backend.Key) (*externalauditstorage.ExternalAuditStorage, error) { item, err := bk.Get(ctx, key) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/externalauditstorage_watcher.go b/lib/services/local/externalauditstorage_watcher.go index af44537fe6ce9..2a610d89ee5f1 100644 --- a/lib/services/local/externalauditstorage_watcher.go +++ b/lib/services/local/externalauditstorage_watcher.go @@ -169,7 +169,7 @@ func (w *ClusterExternalAuditWatcher) watch(ctx context.Context) error { func (w *ClusterExternalAuditWatcher) newWatcher(ctx context.Context) (backend.Watcher, error) { watcher, err := w.backend.NewWatcher(ctx, backend.Watch{ Name: types.KindExternalAuditStorage, - Prefixes: [][]byte{clusterExternalAuditStorageBackendKey}, + Prefixes: []backend.Key{clusterExternalAuditStorageBackendKey}, }) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/generic/generic.go b/lib/services/local/generic/generic.go index e90f9b60467ae..2cc475d1f13fb 100644 --- a/lib/services/local/generic/generic.go +++ b/lib/services/local/generic/generic.go @@ -372,7 +372,7 @@ func (s *Service[T]) MakeBackendItem(resource T, name string) (backend.Item, err } // MakeKey will make a key for the service given a name. -func (s *Service[T]) MakeKey(name string) []byte { +func (s *Service[T]) MakeKey(name string) backend.Key { return backend.NewKey(s.backendPrefix, name) } diff --git a/lib/services/local/generic/helpers.go b/lib/services/local/generic/helpers.go index e681f21deb795..9d647baaa0d75 100644 --- a/lib/services/local/generic/helpers.go +++ b/lib/services/local/generic/helpers.go @@ -58,7 +58,7 @@ type MarshalableResource interface { // signature used elsewhere and therefore may not be the best choice for all use cases, but it // has the benefit of being simpler to use and not requiring the caller to undergo the revision/expiry // ceremony at each call site. -func FastMarshal[T MarshalableResource](key []byte, r T) (backend.Item, error) { +func FastMarshal[T MarshalableResource](key backend.Key, r T) (backend.Item, error) { value, err := utils.FastMarshal(r) if err != nil { return backend.Item{}, err diff --git a/lib/services/local/generic/nonce.go b/lib/services/local/generic/nonce.go index 8d9a37b232775..c1e6c91e9013c 100644 --- a/lib/services/local/generic/nonce.go +++ b/lib/services/local/generic/nonce.go @@ -48,7 +48,7 @@ type nonceProtectedResource interface { // FastUpdateNonceProtectedResource is a helper for updating a resource that is protected by a nonce. The target resource must store // its nonce value in a top-level 'nonce' field in order for correct nonce semantics to be observed. -func FastUpdateNonceProtectedResource[T nonceProtectedResource](ctx context.Context, bk backend.Backend, key []byte, resource T) error { +func FastUpdateNonceProtectedResource[T nonceProtectedResource](ctx context.Context, bk backend.Backend, key backend.Key, resource T) error { if resource.GetNonce() == math.MaxUint64 { return fastUpsertNonceProtectedResource(ctx, bk, key, resource) } @@ -106,7 +106,7 @@ func FastUpdateNonceProtectedResource[T nonceProtectedResource](ctx context.Cont // fastUpsertNonceProtectedResource performs an "upsert" while preserving correct nonce ordering. necessary in order to prevent upserts // from breaking concurrent protected updates. -func fastUpsertNonceProtectedResource[T nonceProtectedResource](ctx context.Context, bk backend.Backend, key []byte, resource T) error { +func fastUpsertNonceProtectedResource[T nonceProtectedResource](ctx context.Context, bk backend.Backend, key backend.Key, resource T) error { const maxRetries = 16 for i := 0; i < maxRetries; i++ { prev, err := bk.Get(ctx, key) diff --git a/lib/services/local/generic/nonce_test.go b/lib/services/local/generic/nonce_test.go index 6989ca1547b15..0dc55fd830686 100644 --- a/lib/services/local/generic/nonce_test.go +++ b/lib/services/local/generic/nonce_test.go @@ -60,7 +60,7 @@ func newNoncedResource(name string, nonce uint64) *noncedResource { } } -func fastGetResource[T types.Resource](ctx context.Context, bk backend.Backend, key []byte) (T, error) { +func fastGetResource[T types.Resource](ctx context.Context, bk backend.Backend, key backend.Key) (T, error) { var value T item, err := bk.Get(ctx, key) diff --git a/lib/services/local/headlessauthn.go b/lib/services/local/headlessauthn.go index 4f0a2ce55e825..a7b4334dc9ac5 100644 --- a/lib/services/local/headlessauthn.go +++ b/lib/services/local/headlessauthn.go @@ -155,6 +155,6 @@ func unmarshalHeadlessAuthentication(data []byte) (*types.HeadlessAuthentication const headlessAuthenticationPrefix = "headless_authentication" -func headlessAuthenticationKey(username, name string) []byte { +func headlessAuthenticationKey(username, name string) backend.Key { return backend.NewKey(headlessAuthenticationPrefix, usersPrefix, username, name) } diff --git a/lib/services/local/headlessauthn_watcher.go b/lib/services/local/headlessauthn_watcher.go index a4ce5c8f7adbd..80240cd8a7e94 100644 --- a/lib/services/local/headlessauthn_watcher.go +++ b/lib/services/local/headlessauthn_watcher.go @@ -204,7 +204,7 @@ func (h *HeadlessAuthenticationWatcher) newWatcher(ctx context.Context) (backend watcher, err := h.identityService.NewWatcher(ctx, backend.Watch{ Name: types.KindHeadlessAuthentication, MetricComponent: types.KindHeadlessAuthentication, - Prefixes: [][]byte{backend.NewKey(headlessAuthenticationPrefix)}, + Prefixes: []backend.Key{backend.NewKey(headlessAuthenticationPrefix)}, }) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/integrations.go b/lib/services/local/integrations.go index f1e22e8f084cd..5d8f340b9bde5 100644 --- a/lib/services/local/integrations.go +++ b/lib/services/local/integrations.go @@ -140,7 +140,7 @@ func (s *IntegrationsService) DeleteIntegration(ctx context.Context, name string // notReferencedByEAS checks that integration [name] is not referenced by any EAS (External Audit Storage) // integration. It should be called under the externalAuditStorageLock only. func notReferencedByEAS(ctx context.Context, bk backend.Backend, name string) error { - for _, key := range [][]byte{draftExternalAuditStorageBackendKey, clusterExternalAuditStorageBackendKey} { + for _, key := range []backend.Key{draftExternalAuditStorageBackendKey, clusterExternalAuditStorageBackendKey} { eas, err := getExternalAuditStorage(ctx, bk, key) if err != nil { if !trace.IsNotFound(err) { diff --git a/lib/services/local/plugin_data.go b/lib/services/local/plugin_data.go index 44dac74849932..795bd610c7d28 100644 --- a/lib/services/local/plugin_data.go +++ b/lib/services/local/plugin_data.go @@ -248,7 +248,7 @@ func itemToPluginData(item backend.Item) (types.PluginData, error) { return data, nil } -func pluginDataKey(kind string, name string) []byte { +func pluginDataKey(kind string, name string) backend.Key { return backend.NewKey(pluginDataPrefix, kind, name, paramsPrefix) } diff --git a/lib/services/local/presence.go b/lib/services/local/presence.go index 3f21eb83e362d..cdbdf29afe370 100644 --- a/lib/services/local/presence.go +++ b/lib/services/local/presence.go @@ -77,7 +77,7 @@ func (s *PresenceService) GetNamespaces() ([]types.Namespace, error) { } out := make([]types.Namespace, 0, len(result.Items)) for _, item := range result.Items { - if !bytes.HasSuffix(item.Key, []byte(paramsPrefix)) { + if !bytes.HasSuffix(item.Key, backend.Key(paramsPrefix)) { continue } ns, err := services.UnmarshalNamespace( @@ -227,7 +227,7 @@ func (s *PresenceService) DeleteServerInfo(ctx context.Context, name string) err return nil } -func serverInfoKey(subkind, name string) []byte { +func serverInfoKey(subkind, name string) backend.Key { switch subkind { case types.SubKindCloudInfo: return backend.NewKey(serverInfoPrefix, cloudLabelsPrefix, name) @@ -868,7 +868,7 @@ Acquire: // initSemaphore attempts to initialize/acquire a semaphore which does not yet exist. // Returns AlreadyExistsError if the semaphore is concurrently created. -func (s *PresenceService) initSemaphore(ctx context.Context, key []byte, leaseID string, req types.AcquireSemaphoreRequest) (*types.SemaphoreLease, error) { +func (s *PresenceService) initSemaphore(ctx context.Context, key backend.Key, leaseID string, req types.AcquireSemaphoreRequest) (*types.SemaphoreLease, error) { // create a new empty semaphore resource configured to specifically match // this acquire request. sem, err := req.ConfigureSemaphore() @@ -899,7 +899,7 @@ func (s *PresenceService) initSemaphore(ctx context.Context, key []byte, leaseID // acquireSemaphore attempts to acquire an existing semaphore. Returns NotFoundError if no semaphore exists, // and CompareFailed if the semaphore was concurrently updated. -func (s *PresenceService) acquireSemaphore(ctx context.Context, key []byte, leaseID string, req types.AcquireSemaphoreRequest) (*types.SemaphoreLease, error) { +func (s *PresenceService) acquireSemaphore(ctx context.Context, key backend.Key, leaseID string, req types.AcquireSemaphoreRequest) (*types.SemaphoreLease, error) { item, err := s.Get(ctx, key) if err != nil { return nil, trace.Wrap(err) @@ -1070,7 +1070,7 @@ func (s *PresenceService) GetSemaphores(ctx context.Context, filter types.Semaph } items = append(items, *item) } else { - var startKey []byte + var startKey backend.Key if filter.SemaphoreKind != "" { startKey = backend.ExactKey(semaphoresPrefix, filter.SemaphoreKind) } else { @@ -1374,7 +1374,7 @@ func (s *PresenceService) KeepAliveServer(ctx context.Context, h types.KeepAlive } // Update the prefix off the type information in the keep alive. - var key []byte + var key backend.Key switch h.GetType() { case constants.KeepAliveNode: key = backend.NewKey(nodesPrefix, h.Namespace, h.Name) diff --git a/lib/services/local/session.go b/lib/services/local/session.go index 594557370d3ad..4e76a72a94c7d 100644 --- a/lib/services/local/session.go +++ b/lib/services/local/session.go @@ -502,10 +502,10 @@ type webTokens struct { log logrus.FieldLogger } -func webSessionKey(sessionID string) (key []byte) { +func webSessionKey(sessionID string) backend.Key { return backend.NewKey(webPrefix, sessionsPrefix, sessionID) } -func webTokenKey(token string) (key []byte) { +func webTokenKey(token string) backend.Key { return backend.NewKey(webPrefix, tokensPrefix, token) } diff --git a/lib/services/local/unstable.go b/lib/services/local/unstable.go index 931bba92b878e..396cccc3ea0cb 100644 --- a/lib/services/local/unstable.go +++ b/lib/services/local/unstable.go @@ -108,7 +108,7 @@ func (s UnstableService) GetSystemRoleAssertions(ctx context.Context, serverID s return set, nil } -func systemRoleAssertionsKey(serverID string, assertionID string) []byte { +func systemRoleAssertionsKey(serverID string, assertionID string) backend.Key { return backend.NewKey(systemRoleAssertionsPrefix, serverID, assertionID) } diff --git a/lib/services/local/userpreferences.go b/lib/services/local/userpreferences.go index 249588df54c50..326134fbf63a0 100644 --- a/lib/services/local/userpreferences.go +++ b/lib/services/local/userpreferences.go @@ -120,7 +120,7 @@ func (u *UserPreferencesService) getUserPreferences(ctx context.Context, usernam } // backendKey returns the backend key for the user preferences for the given username. -func backendKey(username string) []byte { +func backendKey(username string) backend.Key { return backend.NewKey(userPreferencesPrefix, username) } diff --git a/lib/services/local/users.go b/lib/services/local/users.go index 0799a2cd7d527..0be4fafa11841 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -99,7 +99,7 @@ func (s *IdentityService) GetUsers(withSecrets bool) ([]types.User, error) { } var out []types.User for _, item := range result.Items { - if !bytes.HasSuffix(item.Key, []byte(paramsPrefix)) { + if !bytes.HasSuffix(item.Key, backend.Key(paramsPrefix)) { continue } u, err := services.UnmarshalUser( @@ -701,11 +701,11 @@ func (s *IdentityService) GetTeleportUserByWebauthnID(ctx context.Context, webID return user.TeleportUser, nil } -func webauthnLocalAuthKey(user string) []byte { +func webauthnLocalAuthKey(user string) backend.Key { return backend.NewKey(webPrefix, usersPrefix, user, webauthnLocalAuthPrefix) } -func webauthnUserKey(id []byte) []byte { +func webauthnUserKey(id []byte) backend.Key { key := base64.RawURLEncoding.EncodeToString(id) return backend.NewKey(webauthnPrefix, usersPrefix, key) } @@ -759,7 +759,7 @@ func (s *IdentityService) DeleteWebauthnSessionData(ctx context.Context, user, s return trace.Wrap(s.Delete(ctx, sessionDataKey(user, sessionID))) } -func sessionDataKey(user, sessionID string) []byte { +func sessionDataKey(user, sessionID string) backend.Key { return backend.NewKey(webPrefix, usersPrefix, user, webauthnSessionData, sessionID) } @@ -870,7 +870,7 @@ func (s *IdentityService) DeleteGlobalWebauthnSessionData(ctx context.Context, s return nil } -func globalSessionDataKey(scope, id string) []byte { +func globalSessionDataKey(scope, id string) backend.Key { return backend.NewKey(webauthnPrefix, webauthnGlobalSessionData, scope, id) } diff --git a/lib/services/unified_resource.go b/lib/services/unified_resource.go index a6eddcc95aa48..fd2b0271045ac 100644 --- a/lib/services/unified_resource.go +++ b/lib/services/unified_resource.go @@ -202,7 +202,7 @@ func (c *UnifiedResourceCache) getSortTree(sortField string) (*btree.BTreeG[*ite } -func (c *UnifiedResourceCache) getRange(ctx context.Context, startKey []byte, matchFn func(types.ResourceWithLabels) (bool, error), req *proto.ListUnifiedResourcesRequest) ([]resource, string, error) { +func (c *UnifiedResourceCache) getRange(ctx context.Context, startKey backend.Key, matchFn func(types.ResourceWithLabels) (bool, error), req *proto.ListUnifiedResourcesRequest) ([]resource, string, error) { if len(startKey) == 0 { return nil, "", trace.BadParameter("missing parameter startKey") } @@ -218,7 +218,7 @@ func (c *UnifiedResourceCache) getRange(ctx context.Context, startKey []byte, ma return trace.Wrap(err, "getting sort tree") } var iterateRange func(lessOrEqual, greaterThan *item, iterator btree.ItemIteratorG[*item]) - var endKey []byte + var endKey backend.Key if req.SortBy.IsDesc { iterateRange = tree.DescendRange endKey = backend.NewKey(prefix) @@ -269,10 +269,10 @@ func (c *UnifiedResourceCache) getRange(ctx context.Context, startKey []byte, ma return res, nextKey, nil } -func getStartKey(req *proto.ListUnifiedResourcesRequest) []byte { +func getStartKey(req *proto.ListUnifiedResourcesRequest) backend.Key { // if startkey exists, return it if req.StartKey != "" { - return []byte(req.StartKey) + return backend.Key(req.StartKey) } // if startkey doesnt exist, we check the the sort direction. // If sort is descending, startkey is end of the list @@ -372,8 +372,8 @@ func resourceKey(resource types.Resource) string { } type resourceSortKey struct { - byName []byte - byType []byte + byName backend.Key + byType backend.Key } // resourceSortKey will generate a key to be used in the sort trees @@ -704,7 +704,7 @@ func (i *item) Less(iother btree.Item) bool { // prefixItem is used for prefix matches on a B-Tree type prefixItem struct { // prefix is a prefix to match - prefix []byte + prefix backend.Key } // Less is used for Btree operations @@ -721,7 +721,7 @@ type resource interface { type item struct { // Key is a key of the key value item. This will be different based on which sorting tree // the item is in - Key []byte + Key backend.Key // Value will be the resourceKey used in the resources map to get the resource Value string } diff --git a/lib/usagereporter/teleport/aggregating/service.go b/lib/usagereporter/teleport/aggregating/service.go index 1d744d1f01b9d..93b51716295a4 100644 --- a/lib/usagereporter/teleport/aggregating/service.go +++ b/lib/usagereporter/teleport/aggregating/service.go @@ -43,7 +43,7 @@ const ( // userActivityReportKey returns the backend key for a user activity report with // a given UUID and start time, such that reports with an earlier start time // will appear earlier in lexicographic ordering. -func userActivityReportKey(reportUUID uuid.UUID, startTime time.Time) []byte { +func userActivityReportKey(reportUUID uuid.UUID, startTime time.Time) backend.Key { return backend.NewKey(userActivityReportsPrefix, startTime.Format(time.RFC3339), reportUUID.String()) } @@ -79,7 +79,7 @@ func prepareUserActivityReports( // resourcePresenceReportKey returns the backend key for a resource presence report with // a given UUID and start time, such that reports with an earlier start time // will appear earlier in lexicographic ordering. -func resourcePresenceReportKey(reportUUID uuid.UUID, startTime time.Time) []byte { +func resourcePresenceReportKey(reportUUID uuid.UUID, startTime time.Time) backend.Key { return backend.NewKey(ResourcePresenceReportsPrefix, startTime.Format(time.RFC3339), reportUUID.String()) }