2024-06-06 20:08:51 +00:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"log/slog"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/lestrrat-go/jwx/v2/jwa"
|
|
|
|
"github.com/lestrrat-go/jwx/v2/jwt"
|
|
|
|
|
|
|
|
"code.icb4dc0.de/prskr/searcherside/core/ports"
|
2024-06-19 19:19:37 +00:00
|
|
|
"code.icb4dc0.de/prskr/searcherside/internal/cli"
|
2024-06-06 20:08:51 +00:00
|
|
|
)
|
|
|
|
|
2024-06-19 19:19:37 +00:00
|
|
|
var ErrJwtSecretRequired = errors.New("JWT secret is required")
|
2024-06-06 20:08:51 +00:00
|
|
|
|
|
|
|
type TokenHandler struct {
|
|
|
|
Token struct {
|
2024-06-19 19:19:37 +00:00
|
|
|
Secret cli.HexString `name:"secret" help:"JWT secret"`
|
|
|
|
Lifetime time.Duration `name:"lifetime" help:"JWT lifetime" default:"24h"`
|
|
|
|
Subject string `name:"subject" help:"JWT subject" default:"${WHOAMI=nobody}"`
|
|
|
|
Claims []cli.TokenClaim `name:"claims" help:"JWT claims"`
|
2024-06-06 20:08:51 +00:00
|
|
|
} `embed:"" prefix:"token."`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *TokenHandler) Run(stdout ports.STDOUT, logger *slog.Logger) error {
|
|
|
|
now := time.Now().UTC()
|
|
|
|
if len(h.Token.Secret) == 0 {
|
|
|
|
return ErrJwtSecretRequired
|
|
|
|
}
|
|
|
|
|
|
|
|
if tokenLength := len(h.Token.Secret); tokenLength < jwtSecretLength {
|
|
|
|
logger.Warn(
|
|
|
|
"The secret does not have the recommended length",
|
|
|
|
slog.Int("actual_length", tokenLength),
|
|
|
|
slog.Int("recommended_length", jwtSecretLength),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
token := jwt.New()
|
|
|
|
|
|
|
|
for _, claim := range h.Token.Claims {
|
|
|
|
if err := token.Set(claim.Key, claim.Value); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := token.Set(jwt.SubjectKey, h.Token.Subject); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := token.Set(jwt.ExpirationKey, now.Add(h.Token.Lifetime)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
tokenString, err := jwt.Sign(token, jwt.WithKey(jwa.HS256, h.Token.Secret.Raw()))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = fmt.Fprintln(stdout, string(tokenString))
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|