2024-07-29 00:21:07 -04:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"dynatron.me/x/stillbox/pkg/gordio/database"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
)
|
|
|
|
|
2024-07-29 00:58:32 -04:00
|
|
|
type apiKeyAuth interface {
|
2024-08-01 01:01:08 -04:00
|
|
|
// CheckAPIKey validates the provided key and returns the API owner's UserID.
|
2024-07-29 00:58:32 -04:00
|
|
|
// An error is returned if validation fails for any reason.
|
2024-08-01 01:01:08 -04:00
|
|
|
CheckAPIKey(ctx context.Context, key string) (*UserID, error)
|
2024-07-29 00:58:32 -04:00
|
|
|
}
|
|
|
|
|
2024-08-01 01:01:08 -04:00
|
|
|
func (a *authenticator) CheckAPIKey(ctx context.Context, key string) (*UserID, error) {
|
2024-07-29 00:21:07 -04:00
|
|
|
keyUuid, err := uuid.Parse(key)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Str("apikey", key).Msg("cannot parse key")
|
|
|
|
return nil, ErrBadRequest
|
|
|
|
}
|
|
|
|
|
|
|
|
db := database.FromCtx(ctx)
|
|
|
|
apik, err := db.GetAPIKey(ctx, keyUuid)
|
|
|
|
if err != nil {
|
|
|
|
if database.IsNoRows(err) {
|
|
|
|
log.Error().Str("apikey", keyUuid.String()).Msg("no such key")
|
|
|
|
return nil, ErrUnauthorized
|
|
|
|
}
|
|
|
|
|
2024-07-29 00:47:58 -04:00
|
|
|
log.Error().Str("apikey", keyUuid.String()).Err(err).Msg("error looking up key")
|
2024-07-29 00:21:07 -04:00
|
|
|
return nil, ErrInternal
|
|
|
|
}
|
|
|
|
|
|
|
|
if (apik.Disabled != nil && *apik.Disabled) || (apik.Expires.Valid && time.Now().After(apik.Expires.Time)) {
|
|
|
|
log.Error().Str("key", apik.ApiKey.String()).Msg("key disabled")
|
|
|
|
return nil, ErrUnauthorized
|
|
|
|
}
|
|
|
|
|
2024-08-01 01:01:08 -04:00
|
|
|
owner := UserID(apik.Owner)
|
|
|
|
|
|
|
|
return &owner, nil
|
2024-07-29 00:21:07 -04:00
|
|
|
}
|