mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-11-21 05:53:11 -05:00
Remove name prefix in apikeys (#1167)
This commit is contained in:
parent
a115c83cba
commit
18b2ae2c5f
@ -4,10 +4,9 @@ import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
"strings"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
@ -45,7 +44,7 @@ func MapDbKey(key *dbc.Apikey) ApiKeyWToken {
|
||||
CreatedAt: key.CreatedAt,
|
||||
LastUsed: key.LastUsed,
|
||||
},
|
||||
Token: fmt.Sprintf("%s-%s", key.Name, key.Token),
|
||||
Token: key.Token,
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +74,10 @@ func (h *Handler) CreateApiKey(c echo.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, conflict := h.config.EnvApiKeys[req.Name]; conflict {
|
||||
conflict := slices.ContainsFunc(h.config.EnvApiKeys, func(k ApiKeyWToken) bool {
|
||||
return k.Name == req.Name
|
||||
})
|
||||
if conflict {
|
||||
return echo.NewHTTPError(409, "An env apikey is already defined with the same name")
|
||||
}
|
||||
|
||||
@ -174,17 +176,15 @@ func (h *Handler) ListApiKey(c echo.Context) error {
|
||||
}
|
||||
|
||||
func (h *Handler) createApiJwt(apikey string) (string, error) {
|
||||
info := strings.SplitN(apikey, "-", 2)
|
||||
if len(info) != 2 {
|
||||
return "", echo.NewHTTPError(http.StatusForbidden, "Invalid api key format")
|
||||
var key *ApiKeyWToken
|
||||
for _, k := range h.config.EnvApiKeys {
|
||||
if k.Token == apikey {
|
||||
key = &k
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
key, fromEnv := h.config.EnvApiKeys[info[0]]
|
||||
if !fromEnv {
|
||||
dbKey, err := h.db.GetApiKey(context.Background(), dbc.GetApiKeyParams{
|
||||
Name: info[0],
|
||||
Token: info[1],
|
||||
})
|
||||
if key == nil {
|
||||
dbKey, err := h.db.GetApiKey(context.Background(), apikey)
|
||||
if err == pgx.ErrNoRows {
|
||||
return "", echo.NewHTTPError(http.StatusForbidden, "Invalid api key")
|
||||
} else if err != nil {
|
||||
@ -195,7 +195,8 @@ func (h *Handler) createApiJwt(apikey string) (string, error) {
|
||||
h.db.TouchApiKey(context.Background(), dbKey.Pk)
|
||||
}()
|
||||
|
||||
key = MapDbKey(&dbKey)
|
||||
found := MapDbKey(&dbKey)
|
||||
key = &found
|
||||
}
|
||||
|
||||
claims := maps.Clone(key.Claims)
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -31,7 +32,7 @@ type Configuration struct {
|
||||
GuestClaims jwt.MapClaims
|
||||
ProtectedClaims []string
|
||||
ExpirationDelay time.Duration
|
||||
EnvApiKeys map[string]ApiKeyWToken
|
||||
EnvApiKeys []ApiKeyWToken
|
||||
}
|
||||
|
||||
var DefaultConfig = Configuration{
|
||||
@ -39,7 +40,7 @@ var DefaultConfig = Configuration{
|
||||
FirstUserClaims: make(jwt.MapClaims),
|
||||
ProtectedClaims: []string{"permissions"},
|
||||
ExpirationDelay: 30 * 24 * time.Hour,
|
||||
EnvApiKeys: make(map[string]ApiKeyWToken),
|
||||
EnvApiKeys: make([]ApiKeyWToken, 0),
|
||||
}
|
||||
|
||||
func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
||||
@ -137,14 +138,14 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
||||
}
|
||||
|
||||
name = strings.ToLower(name)
|
||||
ret.EnvApiKeys[name] = ApiKeyWToken{
|
||||
ret.EnvApiKeys = append(ret.EnvApiKeys, ApiKeyWToken{
|
||||
ApiKey: ApiKey{
|
||||
Id: uuid.New(),
|
||||
Name: name,
|
||||
Claims: claims,
|
||||
},
|
||||
Token: v[1],
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
apikeys, err := db.ListApiKeys(context.Background())
|
||||
@ -152,7 +153,10 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
||||
return nil, err
|
||||
}
|
||||
for _, key := range apikeys {
|
||||
if _, defined := ret.EnvApiKeys[key.Name]; defined {
|
||||
dup := slices.ContainsFunc(ret.EnvApiKeys, func(k ApiKeyWToken) bool {
|
||||
return k.Name == key.Name
|
||||
})
|
||||
if dup {
|
||||
return nil, fmt.Errorf(
|
||||
"an api key with the name %s is already defined in database. Can't specify a new one via env var",
|
||||
key.Name,
|
||||
|
||||
@ -76,17 +76,11 @@ select
|
||||
from
|
||||
keibi.apikeys
|
||||
where
|
||||
name = $1
|
||||
and token = $2
|
||||
token = $1
|
||||
`
|
||||
|
||||
type GetApiKeyParams struct {
|
||||
Name string `json:"name"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetApiKey(ctx context.Context, arg GetApiKeyParams) (Apikey, error) {
|
||||
row := q.db.QueryRow(ctx, getApiKey, arg.Name, arg.Token)
|
||||
func (q *Queries) GetApiKey(ctx context.Context, token string) (Apikey, error) {
|
||||
row := q.db.QueryRow(ctx, getApiKey, token)
|
||||
var i Apikey
|
||||
err := row.Scan(
|
||||
&i.Pk,
|
||||
|
||||
@ -4,8 +4,7 @@ select
|
||||
from
|
||||
keibi.apikeys
|
||||
where
|
||||
name = $1
|
||||
and token = $2;
|
||||
token = $1;
|
||||
|
||||
-- name: TouchApiKey :exec
|
||||
update
|
||||
|
||||
@ -11,7 +11,7 @@ HTTP 401
|
||||
|
||||
POST {{host}}/keys
|
||||
# this is created from the gh workflow file's env var
|
||||
X-API-KEY: hurl-1234apikey
|
||||
X-API-KEY: 1234apikey
|
||||
{
|
||||
"name": "dryflower",
|
||||
"claims": {
|
||||
@ -32,7 +32,7 @@ jwt: jsonpath "$.token"
|
||||
|
||||
# Duplicates email
|
||||
POST {{host}}/keys
|
||||
X-API-KEY: hurl-1234apikey
|
||||
X-API-KEY: 1234apikey
|
||||
{
|
||||
"name": "dryflower",
|
||||
"claims": {
|
||||
@ -57,5 +57,5 @@ Authorization: Bearer {{jwt}}
|
||||
HTTP 403
|
||||
|
||||
DELETE {{host}}/keys/{{id}}
|
||||
X-API-KEY: hurl-1234apikey
|
||||
X-API-KEY: 1234apikey
|
||||
HTTP 200
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
POST {{host}}/keys
|
||||
# this is created from the gh workflow file's env var
|
||||
X-API-KEY: hurl-1234apikey
|
||||
X-API-KEY: 1234apikey
|
||||
{
|
||||
"name": "dryflower",
|
||||
"claims": {
|
||||
@ -32,5 +32,5 @@ jsonpath "$.items[0].claims.permissions" contains "apikeys.read"
|
||||
# Clean api key
|
||||
|
||||
DELETE {{host}}/keys/{{id}}
|
||||
X-API-KEY: hurl-1234apikey
|
||||
X-API-KEY: 1234apikey
|
||||
HTTP 200
|
||||
|
||||
@ -62,13 +62,11 @@ spec:
|
||||
value: "http://{{ include "kyoo.auth.fullname" . }}:4568/.well-known/jwks.json"
|
||||
- name: JWT_ISSUER
|
||||
value: {{ .Values.kyoo.address | quote }}
|
||||
- name: HELPERVAR_APIKEY
|
||||
- name: KYOO_APIKEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: {{ .Values.kyoo.auth.apikeys.scanner.apikeyKey }}
|
||||
name: {{ .Values.kyoo.auth.apikeys.scanner.existingSecret }}
|
||||
- name: KYOO_APIKEY
|
||||
value: "scanner-$(HELPERVAR_APIKEY)"
|
||||
- name: THEMOVIEDB_API_ACCESS_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
|
||||
@ -115,7 +115,6 @@ kyoo:
|
||||
extra: []
|
||||
# - name: example
|
||||
# existingSecret: bigsecret
|
||||
## value of the apieky should be $name-$apikey
|
||||
# apikeyKey: example_apikey
|
||||
# claims: '{"permissions": ["core.read"]}'
|
||||
|
||||
|
||||
@ -121,7 +121,7 @@ services:
|
||||
# Use this env var once we use mTLS for auth
|
||||
# - KYOO_URL=${KYOO_URL:-http://api:3567/api}
|
||||
- KYOO_URL=${KYOO_URL:-http://traefik:8901/api}
|
||||
- KYOO_APIKEY=scanner-$KEIBI_APIKEY_SCANNER
|
||||
- KYOO_APIKEY=$KEIBI_APIKEY_SCANNER
|
||||
- JWKS_URL=http://auth:4568/.well-known/jwks.json
|
||||
- JWT_ISSUER=${PUBLIC_URL}
|
||||
volumes:
|
||||
|
||||
@ -78,7 +78,7 @@ services:
|
||||
# Use this env var once we use mTLS for auth
|
||||
# - KYOO_URL=${KYOO_URL:-http://api:3567/api}
|
||||
- KYOO_URL=${KYOO_URL:-http://traefik:8901/api}
|
||||
- KYOO_APIKEY=scanner-$KEIBI_APIKEY_SCANNER
|
||||
- KYOO_APIKEY=$KEIBI_APIKEY_SCANNER
|
||||
- JWKS_URL=http://auth:4568/.well-known/jwks.json
|
||||
- JWT_ISSUER=${PUBLIC_URL}
|
||||
volumes:
|
||||
|
||||
@ -11,7 +11,7 @@ LIBRARY_IGNORE_PATTERN=".*/[dD]ownloads?/.*"
|
||||
THEMOVIEDB_API_ACCESS_TOKEN=""
|
||||
|
||||
KYOO_URL="http://api:3567/api"
|
||||
KYOO_APIKEY=scanner-$KEIBI_APIKEY_SCANNER
|
||||
KYOO_APIKEY=$KEIBI_APIKEY_SCANNER
|
||||
|
||||
JWKS_URL="http://auth:4568/.well-known/jwks.json"
|
||||
JWT_ISSUER=$PUBLIC_URL
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user