Add custom claims for first user

This commit is contained in:
Zoe Roux 2025-04-04 21:21:29 +02:00
parent 8ef4fe5e55
commit 431055ec49
No known key found for this signature in database
7 changed files with 61 additions and 12 deletions

View File

@ -7,6 +7,11 @@ KEIBI_PREFIX=""
# path of the private key used to sign jwts. If this is empty, a new one will be generated on startup
RSA_PRIVATE_KEY_PATH=""
# json object with the claims to add to every jwt (this is read when creating a new user)
EXTRA_CLAIMS='{}'
# json object with the claims to add to every jwt of the FIRST user (this can be used to mark the first user as admin).
# Those claims are merged with the `EXTRA_CLAIMS`.
FIRST_USER_CLAIMS='{}'
# The url you can use to reach your kyoo instance. This is used during oidc to redirect users to your instance.
PUBLIC_URL=http://localhost:8901

View File

@ -1,11 +1,12 @@
package main
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"maps"
"os"
"time"
@ -19,11 +20,13 @@ type Configuration struct {
JwtPublicKey *rsa.PublicKey
PublicUrl string
DefaultClaims jwt.MapClaims
FirstUserClaims jwt.MapClaims
ExpirationDelay time.Duration
}
var DefaultConfig = Configuration{
DefaultClaims: make(jwt.MapClaims),
FirstUserClaims: make(jwt.MapClaims),
ExpirationDelay: 30 * 24 * time.Hour,
}
@ -33,6 +36,25 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
ret.PublicUrl = os.Getenv("PUBLIC_URL")
ret.Prefix = os.Getenv("KEIBI_PREFIX")
claims := os.Getenv("EXTRA_CLAIMS")
if claims != "" {
err := json.Unmarshal([]byte(claims), &ret.DefaultClaims)
if err != nil {
return nil, err
}
}
claims = os.Getenv("FIRST_USER_CLAIMS")
if claims != "" {
err := json.Unmarshal([]byte(claims), &ret.FirstUserClaims)
if err != nil {
return nil, err
}
maps.Insert(ret.FirstUserClaims, maps.All(ret.DefaultClaims))
} else {
ret.FirstUserClaims = ret.DefaultClaims
}
rsa_pk_path := os.Getenv("RSA_PRIVATE_KEY_PATH")
if rsa_pk_path != "" {
privateKeyData, err := os.ReadFile(rsa_pk_path)

View File

@ -14,7 +14,15 @@ import (
const createUser = `-- name: CreateUser :one
insert into users(username, email, password, claims)
values ($1, $2, $3, $4)
values ($1, $2, $3, case when not exists (
select
pk, id, username, email, password, claims, created_date, last_seen
from
users) then
$4::jsonb
else
$5::jsonb
end)
returning
pk, id, username, email, password, claims, created_date, last_seen
`
@ -23,7 +31,8 @@ type CreateUserParams struct {
Username string `json:"username"`
Email string `json:"email"`
Password *string `json:"password"`
Claims jwt.MapClaims `json:"claims"`
FirstClaims interface{} `json:"firstClaims"`
Claims interface{} `json:"claims"`
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
@ -31,6 +40,7 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
arg.Username,
arg.Email,
arg.Password,
arg.FirstClaims,
arg.Claims,
)
var i User

View File

@ -51,7 +51,15 @@ where
-- name: CreateUser :one
insert into users(username, email, password, claims)
values ($1, $2, $3, $4)
values ($1, $2, $3, case when not exists (
select
*
from
users) then
sqlc.arg(first_claims)::jsonb
else
sqlc.arg(claims)::jsonb
end)
returning
*;

View File

@ -27,6 +27,9 @@ sql:
go_type:
import: "github.com/google/uuid"
type: "UUID"
- db_type: "jsonb"
go_type:
type: "interface{}"
- column: "users.claims"
go_type:
import: "github.com/golang-jwt/jwt/v5"

View File

@ -212,6 +212,7 @@ func (h *Handler) Register(c echo.Context) error {
Email: req.Email,
Password: &pass,
Claims: h.config.DefaultClaims,
FirstClaims: h.config.FirstUserClaims,
})
if ErrIs(err, pgerrcode.UniqueViolation) {
return echo.NewHTTPError(409, "Email or username already taken")

View File

@ -40,7 +40,7 @@ in
go-migrate
sqlc
go-swag
robotframework-tidy
# robotframework-tidy
bun
pkg-config
node-gyp