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/atomicwrite.go b/lib/backend/atomicwrite.go index c93200fa8ba54..05f987b12d037 100644 --- a/lib/backend/atomicwrite.go +++ b/lib/backend/atomicwrite.go @@ -176,7 +176,7 @@ func Delete() Action { type ConditionalAction struct { // Key is the key against which the associated condition and action are to // be applied. - Key []byte + Key Key // Condition must be one of Exists|NotExists|Revision()|Whatever Condition Condition diff --git a/lib/backend/backend.go b/lib/backend/backend.go index 56c7ea7bbbc09..1490d6eb98236 100644 --- a/lib/backend/backend.go +++ b/lib/backend/backend.go @@ -67,17 +67,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, @@ -90,7 +90,7 @@ type Backend interface { ConditionalUpdate(ctx context.Context, i Item) (*Lease, error) // ConditionalDelete deletes the item by key if the revision matches the stored revision. - ConditionalDelete(ctx context.Context, key []byte, revision string) error + ConditionalDelete(ctx context.Context, key Key, revision string) error // AtomicWrite executes a batch of conditional actions atomically s.t. all actions happen if all // conditions are met, but no actions happen if any condition fails to hold. If one or more conditions @@ -130,7 +130,7 @@ func New(ctx context.Context, backend string, params Params) (Backend, error) { } // 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 } @@ -167,7 +167,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 @@ -196,7 +196,7 @@ func StreamRange(ctx context.Context, bk Backend, startKey, endKey []byte, pageS // err = backend.KeepAlive(ctx, lease, expires) type Lease struct { // Key is the resource identifier. - Key []byte + Key Key // ID is a lease ID, could be empty. // Deprecated: use Revision instead ID int64 @@ -211,7 +211,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 @@ -255,7 +255,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 @@ -308,7 +308,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-- { @@ -322,10 +322,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) } @@ -346,7 +346,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. @@ -362,13 +362,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 @@ -442,7 +442,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...) } @@ -450,12 +450,12 @@ 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))) } // CreateRevision generates a new identifier to be used diff --git a/lib/backend/buffer.go b/lib/backend/buffer.go index 2d52fe1bdfb8c..24211e0b2b1ea 100644 --- a/lib/backend/buffer.go +++ b/lib/backend/buffer.go @@ -220,7 +220,7 @@ func (c *CircularBuffer) fanOutEvent(r Event) { } // RemoveRedundantPrefixes will remove redundant prefixes from the given prefix list. -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 d540705c57d72..02f4a80a13927 100644 --- a/lib/backend/buffer_test.go +++ b/lib/backend/buffer_test.go @@ -20,6 +20,7 @@ package backend import ( "context" + "fmt" "testing" "time" @@ -50,17 +51,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, int64(1), e.Item.ID) + 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(): @@ -103,12 +104,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") } @@ -118,7 +119,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. @@ -130,13 +131,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(): @@ -176,7 +177,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 { @@ -191,7 +192,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(): @@ -202,7 +203,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: @@ -238,29 +239,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 { @@ -278,7 +279,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() @@ -289,11 +290,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, int64(1), e.Item.ID) + require.Equal(t, Key("/a/b/c"), e.Item.Key) case <-time.After(100 * time.Millisecond): t.Fatalf("Timeout waiting for event.") } @@ -321,7 +322,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 @@ -342,11 +343,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, int64(2), e.Item.ID) + require.Equal(t, Key("/2"), e.Item.Key) case <-time.After(100 * time.Millisecond): t.Fatalf("Timeout waiting for event.") } @@ -357,10 +358,10 @@ func TestWatcherTree(t *testing.T) { wt := newWatcherTree() require.False(t, wt.rm(nil)) - w1 := &BufferWatcher{Watch: Watch{Prefixes: [][]byte{[]byte("/a"), []byte("/a/a1"), []byte("/c")}}} + 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 f042bd2303f49..a11e735f0fa1e 100644 --- a/lib/backend/dynamo/dynamodbbk.go +++ b/lib/backend/dynamo/dynamodbbk.go @@ -406,7 +406,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") } @@ -440,7 +440,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 @@ -474,7 +474,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") } @@ -521,7 +521,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 @@ -599,7 +599,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 _, err := b.getKey(ctx, key); err != nil { return err } @@ -628,7 +628,7 @@ func (b *Backend) ConditionalUpdate(ctx context.Context, item backend.Item) (*ba // ConditionalDelete deletes item by key if the provided revision matches // the revision of the item in Dynamo. -func (b *Backend) ConditionalDelete(ctx context.Context, key []byte, rev string) error { +func (b *Backend) ConditionalDelete(ctx context.Context, key backend.Key, rev string) error { if rev == "" { return trace.Wrap(backend.ErrIncorrectRevision) } @@ -919,13 +919,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 is a helper that writes a key/value pair in Dynamo with a given expiration. @@ -985,7 +985,7 @@ func (b *Backend) create(ctx context.Context, item backend.Item, mode int) (stri return r.Revision, 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), @@ -1000,7 +1000,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), @@ -1016,7 +1016,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), @@ -1102,7 +1102,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 3926f7f2cb206..cec359637cc25 100644 --- a/lib/backend/etcdbk/etcd.go +++ b/lib/backend/etcdbk/etcd.go @@ -651,7 +651,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") } @@ -879,7 +879,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) @@ -901,7 +901,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()) @@ -917,7 +917,7 @@ func (b *EtcdBackend) Delete(ctx context.Context, key []byte) error { } // ConditionalDelete deletes the item if it hasn't been modified. -func (b *EtcdBackend) ConditionalDelete(ctx context.Context, prefix []byte, rev string) error { +func (b *EtcdBackend) ConditionalDelete(ctx context.Context, prefix backend.Key, rev string) error { r, err := fromBackendRevision(rev) if err != nil { return trace.Wrap(backend.ErrIncorrectRevision) @@ -942,7 +942,7 @@ func (b *EtcdBackend) ConditionalDelete(ctx context.Context, prefix []byte, rev } // 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") } @@ -1111,10 +1111,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 bfef8c07dc1ec..2367e313ab8a7 100644 --- a/lib/backend/etcdbk/etcd_test.go +++ b/lib/backend/etcdbk/etcd_test.go @@ -117,7 +117,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) @@ -135,7 +135,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 6bb21d067791c..ba6ea8ec3b4bb 100644 --- a/lib/backend/firestore/firestorebk.go +++ b/lib/backend/firestore/firestorebk.go @@ -127,13 +127,13 @@ 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"` - RevisionV2 string `firestore:"revision,omitempty"` - RevisionV1 string `firestore:"-"` + 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"` + RevisionV2 string `firestore:"revision,omitempty"` + RevisionV1 string `firestore:"-"` } func (r *record) updates() []firestore.Update { @@ -194,7 +194,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, @@ -433,7 +433,7 @@ func (b *Backend) Update(ctx context.Context, item backend.Item) (*backend.Lease return backend.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") } @@ -468,7 +468,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) @@ -509,7 +509,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) @@ -519,7 +519,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") } @@ -621,7 +621,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") } @@ -639,7 +639,7 @@ func (b *Backend) Delete(ctx context.Context, key []byte) error { } // ConditionalDelete deletes item by key if the revision matches -func (b *Backend) ConditionalDelete(ctx context.Context, key []byte, rev string) error { +func (b *Backend) ConditionalDelete(ctx context.Context, key backend.Key, rev string) error { if !isRevisionV2(rev) { return b.legacyConditionalDelete(ctx, key, rev) } @@ -685,7 +685,7 @@ func (b *Backend) ConditionalDelete(ctx context.Context, key []byte, rev string) return nil } -func (b *Backend) legacyConditionalDelete(ctx context.Context, key []byte, rev string) error { +func (b *Backend) legacyConditionalDelete(ctx context.Context, key backend.Key, rev string) error { revision, err := fromRevisionV1(rev) if err != nil { return trace.Wrap(backend.ErrIncorrectRevision) @@ -844,7 +844,7 @@ func (b *Backend) Clock() clockwork.Clock { // 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 da773a617d16e..85cb4bcc68236 100644 --- a/lib/backend/helpers.go +++ b/lib/backend/helpers.go @@ -29,20 +29,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 8b89baba8c786..2af379af58e0f 100644 --- a/lib/backend/kubernetes/kubernetes.go +++ b/lib/backend/kubernetes/kubernetes.go @@ -221,7 +221,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() @@ -260,7 +260,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) @@ -352,7 +352,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 c7326eebc59ca..b25f7f2f103a5 100644 --- a/lib/backend/kubernetes/kubernetes_test.go +++ b/lib/backend/kubernetes/kubernetes_test.go @@ -142,7 +142,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 d084ffdcb8027..aabb94fdcda22 100644 --- a/lib/backend/lite/lite.go +++ b/lib/backend/lite/lite.go @@ -590,7 +590,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") } @@ -609,7 +609,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 { q, err := tx.PrepareContext(ctx, "SELECT key, value, expires, modified, revision FROM kv WHERE key = ? AND (expires IS NULL OR expires > ?) LIMIT 1") if err != nil { @@ -630,7 +630,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") } @@ -725,7 +725,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) @@ -760,7 +760,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") } @@ -771,7 +771,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") } @@ -791,7 +791,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 { @@ -860,7 +860,7 @@ func (l *Backend) ConditionalUpdate(ctx context.Context, i backend.Item) (*backe return backend.NewLease(i), nil } -func (l *Backend) ConditionalDelete(ctx context.Context, key []byte, revision string) error { +func (l *Backend) ConditionalDelete(ctx context.Context, key backend.Key, revision string) error { if len(key) == 0 || revision == "" { return trace.Wrap(backend.ErrIncorrectRevision) } diff --git a/lib/backend/lite/periodic.go b/lib/backend/lite/periodic.go index f099217e91edc..055aa951705ef 100644 --- a/lib/backend/lite/periodic.go +++ b/lib/backend/lite/periodic.go @@ -83,7 +83,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 04c7327b953ae..af4f3df8dea18 100644 --- a/lib/backend/memory/item.go +++ b/lib/backend/memory/item.go @@ -50,7 +50,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 1b199c1023d47..86046f0a63b2d 100644 --- a/lib/backend/memory/memory.go +++ b/lib/backend/memory/memory.go @@ -184,7 +184,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") } @@ -250,7 +250,7 @@ func (m *Memory) Put(ctx context.Context, i backend.Item) (*backend.Lease, 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") } @@ -275,7 +275,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") } @@ -300,7 +300,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") } @@ -387,7 +387,7 @@ func (m *Memory) CompareAndSwap(ctx context.Context, expected backend.Item, repl return backend.NewLease(replaceWith), nil } -func (m *Memory) ConditionalDelete(ctx context.Context, key []byte, rev string) error { +func (m *Memory) ConditionalDelete(ctx context.Context, key backend.Key, rev string) error { if len(key) == 0 || (rev == "" && !m.Mirror) { return trace.Wrap(backend.ErrIncorrectRevision) } @@ -455,7 +455,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 7a0acb37f3fd7..8d5489d60b9ca 100644 --- a/lib/backend/pgbk/pgbk.go +++ b/lib/backend/pgbk/pgbk.go @@ -386,7 +386,7 @@ func (b *Backend) ConditionalUpdate(ctx context.Context, i backend.Item) (*backe } // 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 @@ -433,7 +433,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 } @@ -485,7 +485,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)) @@ -504,7 +504,7 @@ func (b *Backend) Delete(ctx context.Context, key []byte) error { return nil } -func (b *Backend) ConditionalDelete(ctx context.Context, key []byte, rev string) error { +func (b *Backend) ConditionalDelete(ctx context.Context, key backend.Key, rev string) error { expectedRevision, ok := revisionFromString(rev) if !ok { return trace.Wrap(backend.ErrIncorrectRevision) @@ -531,7 +531,7 @@ func (b *Backend) ConditionalDelete(ctx context.Context, key []byte, rev string) } // 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 ca2c13ede035d..865eb769d5d3b 100644 --- a/lib/backend/pgbk/wal2json_test.go +++ b/lib/backend/pgbk/wal2json_test.go @@ -157,7 +157,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), Revision: revisionToString(rev), @@ -182,7 +182,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), Revision: revisionToString(rev), @@ -211,13 +211,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), @@ -255,7 +255,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 ea4d4b2717da2..71d29b4113a20 100644 --- a/lib/backend/report.go +++ b/lib/backend/report.go @@ -126,7 +126,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", @@ -268,7 +268,7 @@ func (s *Reporter) ConditionalUpdate(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", @@ -319,7 +319,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", @@ -346,7 +346,7 @@ func (s *Reporter) Delete(ctx context.Context, key []byte) error { } // ConditionalDelete deletes the item by key if the revision matches the stored revision. -func (s *Reporter) ConditionalDelete(ctx context.Context, key []byte, revision string) error { +func (s *Reporter) ConditionalDelete(ctx context.Context, key Key, revision string) error { ctx, span := s.Tracer.Start( ctx, "backend/ConditionalDelete", @@ -427,7 +427,7 @@ func (s *Reporter) AtomicWrite(ctx context.Context, condacts []ConditionalAction } // 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", @@ -522,7 +522,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 } @@ -592,7 +592,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 efebba3b04483..20cc0ea46453f 100644 --- a/lib/backend/sanitize.go +++ b/lib/backend/sanitize.go @@ -42,12 +42,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 @@ -73,7 +73,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) } @@ -118,7 +118,7 @@ func (s *Sanitizer) ConditionalUpdate(ctx context.Context, i Item) (*Lease, erro } // 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) } @@ -136,7 +136,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) } @@ -144,7 +144,7 @@ func (s *Sanitizer) Delete(ctx context.Context, key []byte) error { } // ConditionalDelete deletes the item by key if the revision matches the stored revision. -func (s *Sanitizer) ConditionalDelete(ctx context.Context, key []byte, revision string) error { +func (s *Sanitizer) ConditionalDelete(ctx context.Context, key Key, revision string) error { if !isKeySafe(key) { return trace.BadParameter(errorMessage, key) } @@ -152,7 +152,7 @@ func (s *Sanitizer) ConditionalDelete(ctx context.Context, key []byte, revision } // 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 6c9b534d941fe..34b84b57a33df 100644 --- a/lib/backend/sanitize_test.go +++ b/lib/backend/sanitize_test.go @@ -146,11 +146,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 @@ -176,15 +176,15 @@ 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 } -func (n *nopBackend) ConditionalDelete(ctx context.Context, key []byte, revision string) error { +func (n *nopBackend) ConditionalDelete(ctx context.Context, key Key, revision string) error { return nil } -func (n *nopBackend) DeleteRange(_ context.Context, _ []byte, _ []byte) error { +func (n *nopBackend) DeleteRange(_ context.Context, _ Key, _ Key) error { return nil } diff --git a/lib/backend/test/atomicwrite_shim.go b/lib/backend/test/atomicwrite_shim.go index 94d2255c1f0ba..acfacf498f2aa 100644 --- a/lib/backend/test/atomicwrite_shim.go +++ b/lib/backend/test/atomicwrite_shim.go @@ -49,7 +49,7 @@ func RunBackendComplianceSuiteWithAtomicWriteShim(t *testing.T, newBackend Const }) } -// atomciWriteShim reimplements all single-write backend methods as calls to AtomicWrite. +// AtomicWriteShim reimplements all single-write backend methods as calls to AtomicWrite. type AtomicWriteShim struct { backend.Backend sentinel []byte @@ -182,7 +182,7 @@ func (a AtomicWriteShim) Update(ctx context.Context, i backend.Item) (*backend.L // Delete deletes item by key, returns NotFound error // if item does not exist -func (a AtomicWriteShim) Delete(ctx context.Context, key []byte) error { +func (a AtomicWriteShim) Delete(ctx context.Context, key backend.Key) error { _, err := a.AtomicWrite(ctx, []backend.ConditionalAction{ a.sca(), { @@ -226,7 +226,7 @@ func (a AtomicWriteShim) ConditionalUpdate(ctx context.Context, i backend.Item) } // ConditionalDelete deletes the item by key if the revision matches the stored revision. -func (a AtomicWriteShim) ConditionalDelete(ctx context.Context, key []byte, revision string) error { +func (a AtomicWriteShim) ConditionalDelete(ctx context.Context, key backend.Key, revision string) error { _, err := a.AtomicWrite(ctx, []backend.ConditionalAction{ a.sca(), { diff --git a/lib/backend/test/suite.go b/lib/backend/test/suite.go index 32b1948edd52d..e5c0582bd52a8 100644 --- a/lib/backend/test/suite.go +++ b/lib/backend/test/suite.go @@ -511,7 +511,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()) }() @@ -581,7 +581,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()) }() @@ -711,7 +711,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(): @@ -760,7 +760,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 @@ -773,7 +773,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()) @@ -1031,7 +1031,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()) }() @@ -1188,7 +1188,7 @@ func testConditionalUpdate(t *testing.T, newBackend Constructor) { } } -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, @@ -1219,9 +1219,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 4769f0076f8de..6079a815b4c0d 100644 --- a/lib/backend/wrap.go +++ b/lib/backend/wrap.go @@ -66,7 +66,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) } @@ -95,7 +95,7 @@ func (s *Wrapper) ConditionalUpdate(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) } @@ -109,17 +109,17 @@ 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) } // ConditionalDelete deletes item by key if revisions match. -func (s *Wrapper) ConditionalDelete(ctx context.Context, key []byte, revision string) error { +func (s *Wrapper) ConditionalDelete(ctx context.Context, key Key, revision string) error { return s.backend.ConditionalDelete(ctx, key, revision) } // 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 f4c75a0328173..e762bf5a69f2f 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -6397,7 +6397,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 8da052436b30a..03fd7b469f917 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -1205,7 +1205,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 5116527ebb94a..ebb528ce0f965 100644 --- a/lib/services/local/dynamic_access.go +++ b/lib/services/local/dynamic_access.go @@ -488,11 +488,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 8438aff8bb2de..8fc889e7b7c2a 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -63,7 +63,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 { @@ -351,26 +351,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 @@ -715,7 +715,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) && @@ -785,15 +785,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 } @@ -831,7 +831,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) && @@ -1345,14 +1345,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) } @@ -1408,14 +1408,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) } @@ -2337,7 +2337,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)) @@ -2346,7 +2346,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 898f5866ee4af..9815db88ee923 100644 --- a/lib/services/local/externalauditstorage.go +++ b/lib/services/local/externalauditstorage.go @@ -277,7 +277,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) @@ -292,7 +292,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 f5c411945cb1a..641f1bcd03e88 100644 --- a/lib/services/local/externalauditstorage_watcher.go +++ b/lib/services/local/externalauditstorage_watcher.go @@ -172,7 +172,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 cfd5e2990dfb4..f1c8a984d3501 100644 --- a/lib/services/local/generic/generic.go +++ b/lib/services/local/generic/generic.go @@ -194,7 +194,7 @@ func (s *Service[T]) listResourcesReturnNextResourceWithKey(ctx context.Context, } out := make([]T, 0, len(result.Items)) - var lastKey []byte + var lastKey backend.Key for _, item := range result.Items { resource, err := s.unmarshalFunc(item.Value, services.WithRevision(item.Revision), services.WithResourceID(item.ID)) if err != nil { @@ -231,7 +231,7 @@ func (s *Service[T]) ListResourcesWithFilter(ctx context.Context, pageSize int, limit := pageSize + 1 var resources []T - var lastKey []byte + var lastKey backend.Key if err := backend.IterateRange( ctx, s.backend, @@ -449,7 +449,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 f48cdea896f9c..033ffc5d70303 100644 --- a/lib/services/local/generic/nonce.go +++ b/lib/services/local/generic/nonce.go @@ -50,7 +50,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) } @@ -108,7 +108,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 5bc6353c087e0..0d7bf4270d2f7 100644 --- a/lib/services/local/generic/nonce_test.go +++ b/lib/services/local/generic/nonce_test.go @@ -62,7 +62,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 2c2cf51e4e3e0..880d0434b59e9 100644 --- a/lib/services/local/headlessauthn.go +++ b/lib/services/local/headlessauthn.go @@ -157,6 +157,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 3cb060576a237..7b6438dd497fe 100644 --- a/lib/services/local/headlessauthn_watcher.go +++ b/lib/services/local/headlessauthn_watcher.go @@ -205,7 +205,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/plugin_data.go b/lib/services/local/plugin_data.go index 2c40f8e88c9c7..2f8404c9bc378 100644 --- a/lib/services/local/plugin_data.go +++ b/lib/services/local/plugin_data.go @@ -250,7 +250,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 35118949dcb55..12c5a6f8e4271 100644 --- a/lib/services/local/presence.go +++ b/lib/services/local/presence.go @@ -79,7 +79,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( @@ -229,7 +229,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) @@ -568,7 +568,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() @@ -599,7 +599,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) @@ -770,7 +770,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 { @@ -1074,7 +1074,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 43ce714107963..57115d14e79e8 100644 --- a/lib/services/local/session.go +++ b/lib/services/local/session.go @@ -509,10 +509,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/trust.go b/lib/services/local/trust.go index d41d087be50c8..ab02aec40064c 100644 --- a/lib/services/local/trust.go +++ b/lib/services/local/trust.go @@ -728,7 +728,7 @@ func (s *CA) DeleteAllRemoteClusters() error { } // catToItem builds a backend.Item corresponding to the supplied CA. -func caToItem(key []byte, ca types.CertAuthority) (backend.Item, error) { +func caToItem(key backend.Key, ca types.CertAuthority) (backend.Item, error) { value, err := services.MarshalCertAuthority(ca) if err != nil { return backend.Item{}, trace.Wrap(err) @@ -744,12 +744,12 @@ func caToItem(key []byte, ca types.CertAuthority) (backend.Item, error) { } // activeCAKey builds the active key variant for the supplied ca id. -func activeCAKey(id types.CertAuthID) []byte { +func activeCAKey(id types.CertAuthID) backend.Key { return backend.NewKey(authoritiesPrefix, string(id.Type), id.DomainName) } // inactiveCAKey builds the inactive key variant for the supplied ca id. -func inactiveCAKey(id types.CertAuthID) []byte { +func inactiveCAKey(id types.CertAuthID) backend.Key { return backend.NewKey(authoritiesPrefix, deactivatedPrefix, string(id.Type), id.DomainName) } diff --git a/lib/services/local/unstable.go b/lib/services/local/unstable.go index cbce002b39217..de3731fff13d7 100644 --- a/lib/services/local/unstable.go +++ b/lib/services/local/unstable.go @@ -110,7 +110,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 85a100c38266b..53bacfee1bb86 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 6c66359e00a21..f6a6d69b05af9 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -241,7 +241,7 @@ func (s *IdentityService) streamUsersWithSecrets(itemStream stream.Stream[backen // streamUsersWithoutSecrets is a helper that converts a stream of backend items over the user range into a stream of // user resources without any included secrets. func (s *IdentityService) streamUsersWithoutSecrets(itemStream stream.Stream[backend.Item]) stream.Stream[*types.UserV2] { - suffix := []byte(paramsPrefix) + suffix := backend.Key(paramsPrefix) userStream := stream.FilterMap(itemStream, func(item backend.Item) (*types.UserV2, bool) { if !bytes.HasSuffix(item.Key, suffix) { return nil, false @@ -271,7 +271,7 @@ func (s *IdentityService) GetUsers(ctx context.Context, withSecrets bool) ([]typ } 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( @@ -984,11 +984,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) } @@ -1042,7 +1042,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) } @@ -1153,7 +1153,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 c3b72888d4efe..1410612dfc0ce 100644 --- a/lib/services/unified_resource.go +++ b/lib/services/unified_resource.go @@ -192,7 +192,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") } @@ -208,7 +208,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) @@ -259,10 +259,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 @@ -362,8 +362,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 @@ -701,7 +701,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 @@ -718,7 +718,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 180b4815a1830..586688826cc12 100644 --- a/lib/usagereporter/teleport/aggregating/service.go +++ b/lib/usagereporter/teleport/aggregating/service.go @@ -47,7 +47,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()) } @@ -83,7 +83,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()) }