fix(docs): convert APIKey to string EE-6199 (#10943)

pull/10951/head
Dakota Walsh 2024-01-15 11:59:39 +13:00 committed by GitHub
parent d750389c67
commit 488fcc7cc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 45 additions and 45 deletions

View File

@ -6,11 +6,11 @@ import (
// APIKeyService represents a service for managing API keys.
type APIKeyService interface {
HashRaw(rawKey string) []byte
HashRaw(rawKey string) string
GenerateApiKey(user portainer.User, description string) (string, *portainer.APIKey, error)
GetAPIKey(apiKeyID portainer.APIKeyID) (*portainer.APIKey, error)
GetAPIKeys(userID portainer.UserID) ([]portainer.APIKey, error)
GetDigestUserAndKey(digest []byte) (portainer.User, portainer.APIKey, error)
GetDigestUserAndKey(digest string) (portainer.User, portainer.APIKey, error)
UpdateAPIKey(apiKey *portainer.APIKey) error
DeleteAPIKey(apiKeyID portainer.APIKeyID) error
InvalidateUserKeyCache(userId portainer.UserID) bool

View File

@ -33,8 +33,8 @@ func NewAPIKeyCache(cacheSize int) *apiKeyCache {
// Get returns the user/key associated to an api-key's digest
// This is required because HTTP requests will contain the digest of the API key in header,
// the digest value must be mapped to a portainer user.
func (c *apiKeyCache) Get(digest []byte) (portainer.User, portainer.APIKey, bool) {
val, ok := c.cache.Get(string(digest))
func (c *apiKeyCache) Get(digest string) (portainer.User, portainer.APIKey, bool) {
val, ok := c.cache.Get(digest)
if !ok {
return portainer.User{}, portainer.APIKey{}, false
}
@ -44,23 +44,23 @@ func (c *apiKeyCache) Get(digest []byte) (portainer.User, portainer.APIKey, bool
}
// Set persists a user/key entry to the cache
func (c *apiKeyCache) Set(digest []byte, user portainer.User, apiKey portainer.APIKey) {
c.cache.Add(string(digest), entry{
func (c *apiKeyCache) Set(digest string, user portainer.User, apiKey portainer.APIKey) {
c.cache.Add(digest, entry{
user: user,
apiKey: apiKey,
})
}
// Delete evicts a digest's user/key entry key from the cache
func (c *apiKeyCache) Delete(digest []byte) {
c.cache.Remove(string(digest))
func (c *apiKeyCache) Delete(digest string) {
c.cache.Remove(digest)
}
// InvalidateUserKeyCache loops through all the api-keys associated to a user and removes them from the cache
func (c *apiKeyCache) InvalidateUserKeyCache(userId portainer.UserID) bool {
present := false
for _, k := range c.cache.Keys() {
user, _, _ := c.Get([]byte(k.(string)))
user, _, _ := c.Get(k.(string))
if user.ID == userId {
present = c.cache.Remove(k)
}

View File

@ -17,19 +17,19 @@ func Test_apiKeyCacheGet(t *testing.T) {
keyCache.cache.Add(string(""), entry{user: portainer.User{}, apiKey: portainer.APIKey{}})
tests := []struct {
digest []byte
digest string
found bool
}{
{
digest: []byte("foo"),
digest: "foo",
found: true,
},
{
digest: []byte(""),
digest: "",
found: true,
},
{
digest: []byte("bar"),
digest: "bar",
found: false,
},
}
@ -48,11 +48,11 @@ func Test_apiKeyCacheSet(t *testing.T) {
keyCache := NewAPIKeyCache(10)
// pre-populate cache
keyCache.Set([]byte("bar"), portainer.User{ID: 2}, portainer.APIKey{})
keyCache.Set([]byte("foo"), portainer.User{ID: 1}, portainer.APIKey{})
keyCache.Set("bar", portainer.User{ID: 2}, portainer.APIKey{})
keyCache.Set("foo", portainer.User{ID: 1}, portainer.APIKey{})
// overwrite existing entry
keyCache.Set([]byte("foo"), portainer.User{ID: 3}, portainer.APIKey{})
keyCache.Set("foo", portainer.User{ID: 3}, portainer.APIKey{})
val, ok := keyCache.cache.Get(string("bar"))
is.True(ok)
@ -74,14 +74,14 @@ func Test_apiKeyCacheDelete(t *testing.T) {
t.Run("Delete an existing entry", func(t *testing.T) {
keyCache.cache.Add(string("foo"), entry{user: portainer.User{ID: 1}, apiKey: portainer.APIKey{}})
keyCache.Delete([]byte("foo"))
keyCache.Delete("foo")
_, ok := keyCache.cache.Get(string("foo"))
is.False(ok)
})
t.Run("Delete a non-existing entry", func(t *testing.T) {
nonPanicFunc := func() { keyCache.Delete([]byte("non-existent-key")) }
nonPanicFunc := func() { keyCache.Delete("non-existent-key") }
is.NotPanics(nonPanicFunc)
})
}
@ -131,16 +131,16 @@ func Test_apiKeyCacheLRU(t *testing.T) {
keyCache := NewAPIKeyCache(test.cacheLen)
for _, key := range test.key {
keyCache.Set([]byte(key), portainer.User{ID: 1}, portainer.APIKey{})
keyCache.Set(key, portainer.User{ID: 1}, portainer.APIKey{})
}
for _, key := range test.foundKeys {
_, _, found := keyCache.Get([]byte(key))
_, _, found := keyCache.Get(key)
is.True(found, "Key %s not found", key)
}
for _, key := range test.evictedKeys {
_, _, found := keyCache.Get([]byte(key))
_, _, found := keyCache.Get(key)
is.False(found, "key %s should have been evicted", key)
}
})

View File

@ -32,9 +32,9 @@ func NewAPIKeyService(apiKeyRepository dataservices.APIKeyRepository, userReposi
}
// HashRaw computes a hash digest of provided raw API key.
func (a *apiKeyService) HashRaw(rawKey string) []byte {
func (a *apiKeyService) HashRaw(rawKey string) string {
hashDigest := sha256.Sum256([]byte(rawKey))
return hashDigest[:]
return base64.StdEncoding.EncodeToString(hashDigest[:])
}
// GenerateApiKey generates a raw API key for a user (for one-time display).
@ -77,7 +77,7 @@ func (a *apiKeyService) GetAPIKeys(userID portainer.UserID) ([]portainer.APIKey,
// GetDigestUserAndKey returns the user and api-key associated to a specified hash digest.
// A cache lookup is performed first; if the user/api-key is not found in the cache, respective database lookups are performed.
func (a *apiKeyService) GetDigestUserAndKey(digest []byte) (portainer.User, portainer.APIKey, error) {
func (a *apiKeyService) GetDigestUserAndKey(digest string) (portainer.User, portainer.APIKey, error) {
// get api key from cache if possible
cachedUser, cachedKey, ok := a.cache.Get(digest)
if ok {

View File

@ -2,6 +2,7 @@ package apikey
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"strings"
"testing"
@ -68,7 +69,7 @@ func Test_GenerateApiKey(t *testing.T) {
generatedDigest := sha256.Sum256([]byte(rawKey))
is.Equal(apiKey.Digest, generatedDigest[:])
is.Equal(apiKey.Digest, base64.StdEncoding.EncodeToString(generatedDigest[:]))
})
}

View File

@ -1,7 +1,6 @@
package apikeyrepository
import (
"bytes"
"errors"
"fmt"
@ -37,7 +36,7 @@ func NewService(connection portainer.Connection) (*Service, error) {
// GetAPIKeysByUserID returns a slice containing all the APIKeys a user has access to.
func (service *Service) GetAPIKeysByUserID(userID portainer.UserID) ([]portainer.APIKey, error) {
var result = make([]portainer.APIKey, 0)
result := make([]portainer.APIKey, 0)
err := service.Connection.GetAll(
BucketName,
@ -61,7 +60,7 @@ func (service *Service) GetAPIKeysByUserID(userID portainer.UserID) ([]portainer
// GetAPIKeyByDigest returns the API key for the associated digest.
// Note: there is a 1-to-1 mapping of api-key and digest
func (service *Service) GetAPIKeyByDigest(digest []byte) (*portainer.APIKey, error) {
func (service *Service) GetAPIKeyByDigest(digest string) (*portainer.APIKey, error) {
var k *portainer.APIKey
stop := fmt.Errorf("ok")
err := service.Connection.GetAll(
@ -73,7 +72,7 @@ func (service *Service) GetAPIKeyByDigest(digest []byte) (*portainer.APIKey, err
log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to APIKey object")
return nil, fmt.Errorf("failed to convert to APIKey object: %s", obj)
}
if bytes.Equal(key.Digest, digest) {
if key.Digest == digest {
k = key
return nil, stop
}

View File

@ -152,7 +152,7 @@ type (
APIKeyRepository interface {
BaseCRUD[portainer.APIKey, portainer.APIKeyID]
GetAPIKeysByUserID(userID portainer.UserID) ([]portainer.APIKey, error)
GetAPIKeyByDigest(digest []byte) (*portainer.APIKey, error)
GetAPIKeyByDigest(digest string) (*portainer.APIKey, error)
}
// SettingsService represents a service for managing application settings

View File

@ -64,5 +64,5 @@ func (handler *Handler) userGetAccessTokens(w http.ResponseWriter, r *http.Reque
// hideAPIKeyFields remove the digest from the API key (it is not needed in the response)
func hideAPIKeyFields(apiKey *portainer.APIKey) {
apiKey.Digest = nil
apiKey.Digest = ""
}

View File

@ -68,7 +68,7 @@ func Test_userGetAccessTokens(t *testing.T) {
is.Len(resp, 1)
if len(resp) == 1 {
is.Nil(resp[0].Digest)
is.Equal(resp[0].Digest, "")
is.Equal(apiKey.ID, resp[0].ID)
is.Equal(apiKey.UserID, resp[0].UserID)
is.Equal(apiKey.Prefix, resp[0].Prefix)
@ -129,10 +129,10 @@ func Test_hideAPIKeyFields(t *testing.T) {
UserID: 2,
Prefix: "abc",
Description: "test",
Digest: nil,
Digest: "",
}
hideAPIKeyFields(apiKey)
is.Nil(apiKey.Digest, "digest should be cleared when hiding api key fields")
is.Equal(apiKey.Digest, "", "digest should be cleared when hiding api key fields")
}

View File

@ -32,7 +32,7 @@ type (
// Authorizations represents a set of authorizations associated to a role
Authorizations map[Authorization]bool
//AutoUpdateSettings represents the git auto sync config for stack deployment
// AutoUpdateSettings represents the git auto sync config for stack deployment
AutoUpdateSettings struct {
// Auto update interval
Interval string `example:"1m30s"`
@ -311,7 +311,7 @@ type (
ConfigHash string `json:"ConfigHash"`
}
//EdgeStack represents an edge stack
// EdgeStack represents an edge stack
EdgeStack struct {
// EdgeStack Identifier
ID EdgeStackID `json:"Id" example:"1"`
@ -335,7 +335,7 @@ type (
EdgeStackDeploymentType int
//EdgeStackID represents an edge stack id
// EdgeStackID represents an edge stack id
EdgeStackID int
EdgeStackStatusDetails struct {
@ -348,7 +348,7 @@ type (
ImagesPulled bool
}
//EdgeStackStatus represents an edge stack status
// EdgeStackStatus represents an edge stack status
EdgeStackStatus struct {
Status []EdgeStackDeploymentStatus
EndpointID EndpointID
@ -372,7 +372,7 @@ type (
RollbackTo *int
}
//EdgeStackStatusType represents an edge stack status type
// EdgeStackStatusType represents an edge stack status type
EdgeStackStatusType int
PendingActionsID int
@ -905,7 +905,7 @@ type (
Prefix string `json:"prefix"` // API key identifier (7 char prefix)
DateCreated int64 `json:"dateCreated"` // Unix timestamp (UTC) when the API key was created
LastUsed int64 `json:"lastUsed"` // Unix timestamp (UTC) when the API key was last used
Digest []byte `json:"digest,omitempty"` // Digest represents SHA256 hash of the raw API key
Digest string `json:"digest,omitempty"` // Digest represents SHA256 hash of the raw API key
}
// Schedule represents a scheduled job.
@ -1657,7 +1657,7 @@ const (
AuthenticationInternal
// AuthenticationLDAP represents the LDAP authentication method (authentication against a LDAP server)
AuthenticationLDAP
//AuthenticationOAuth represents the OAuth authentication method (authentication against a authorization server)
// AuthenticationOAuth represents the OAuth authentication method (authentication against a authorization server)
AuthenticationOAuth
)
@ -1697,13 +1697,13 @@ const (
const (
// EdgeStackStatusPending represents a pending edge stack
EdgeStackStatusPending EdgeStackStatusType = iota
//EdgeStackStatusDeploymentReceived represents an edge environment which received the edge stack deployment
// EdgeStackStatusDeploymentReceived represents an edge environment which received the edge stack deployment
EdgeStackStatusDeploymentReceived
//EdgeStackStatusError represents an edge environment which failed to deploy its edge stack
// EdgeStackStatusError represents an edge environment which failed to deploy its edge stack
EdgeStackStatusError
//EdgeStackStatusAcknowledged represents an acknowledged edge stack
// EdgeStackStatusAcknowledged represents an acknowledged edge stack
EdgeStackStatusAcknowledged
//EdgeStackStatusRemoved represents a removed edge stack
// EdgeStackStatusRemoved represents a removed edge stack
EdgeStackStatusRemoved
// StatusRemoteUpdateSuccess represents a successfully updated edge stack
EdgeStackStatusRemoteUpdateSuccess