Add a middleware in keibi to convert session token to jwt

This commit is contained in:
Zoe Roux 2025-03-30 21:49:43 +02:00
parent 411f6dcfba
commit 92753b72d3
No known key found for this signature in database
3 changed files with 48 additions and 12 deletions

View File

@ -34,12 +34,24 @@ func (h *Handler) CreateJwt(c echo.Context) error {
} }
token := auth[len("Bearer "):] token := auth[len("Bearer "):]
jwt, err := h.createJwt(token)
if err != nil {
return err
}
c.Response().Header().Add("Authorization", fmt.Sprintf("Bearer %s", jwt))
return c.JSON(http.StatusOK, Jwt{
Token: &jwt,
})
}
func (h *Handler) createJwt(token string) (string, error) {
session, err := h.db.GetUserFromToken(context.Background(), token) session, err := h.db.GetUserFromToken(context.Background(), token)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusForbidden, "Invalid token") return "", echo.NewHTTPError(http.StatusForbidden, "Invalid token")
} }
if session.LastUsed.Add(h.config.ExpirationDelay).Compare(time.Now().UTC()) < 0 { if session.LastUsed.Add(h.config.ExpirationDelay).Compare(time.Now().UTC()) < 0 {
return echo.NewHTTPError(http.StatusForbidden, "Token has expired") return "", echo.NewHTTPError(http.StatusForbidden, "Token has expired")
} }
go func() { go func() {
@ -61,22 +73,19 @@ func (h *Handler) CreateJwt(c echo.Context) error {
jwt := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) jwt := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
t, err := jwt.SignedString(h.config.JwtPrivateKey) t, err := jwt.SignedString(h.config.JwtPrivateKey)
if err != nil { if err != nil {
return err return "", err
} }
c.Response().Header().Add("Authorization", fmt.Sprintf("Bearer %s", t)) return t, nil
return c.JSON(http.StatusOK, Jwt{
Token: &t,
})
} }
// only used for the swagger doc // only used for the swagger doc
type JwkSet struct { type JwkSet struct {
Keys []struct { Keys []struct {
E string `json:"e" example:"AQAB"` E string `json:"e" example:"AQAB"`
KeyOps []string `json:"key_ops" example:"[verify]"` KeyOps []string `json:"key_ops" example:"[verify]"`
Kty string `json:"kty" example:"RSA"` Kty string `json:"kty" example:"RSA"`
N string `json:"n" example:"oBcXcJUR-Sb8_b4qIj28LRAPxdF_6odRr52K5-ymiEkR2DOlEuXBtM-biWxPESW-U-zhfHzdVLf6ioy5xL0bJTh8BMIorkrDliN3vb81jCvyOMgZ7ATMJpMAQMmSDN7sL3U45r22FaoQufCJMQHmUsZPecdQSgj2aFBiRXxsLleYlSezdBVT_gKH-coqeYXSC_hk-ezSq4aDZ10BlDnZ-FA7-ES3T7nBmJEAU7KDAGeSvbYAfYimOW0r-Vc0xQNuwGCfzZtSexKXDbYbNwOVo3SjfCabq-gMfap_owcHbKicGBZu1LDlh7CpkmLQf_kv6GihM2LWFFh6Vwg2cltiwF22EIPlUDtYTkUR0qRkdNJaNkwV5Vv_6r3pzSmu5ovRriKtlrvJMjlTnLb4_ltsge3fw5Z34cJrsp094FbUc2O6Or4FGEXUldieJCnVRhs2_h6SDcmeMXs1zfvE5GlDnq8tZV6WMJ5Sb4jNO7rs_hTkr23_E6mVg-DdtozGfqzRzhIjPym6D_jVfR6dZv5W0sKwOHRmT7nYq-C7b2sAwmNNII296M4Rq-jn0b5pgSeMDYbIpbIA4thU8LYU0lBZp_ZVwWKG1RFZDxz3k9O5UVth2kTpTWlwn0hB1aAvgXHo6in1CScITGA72p73RbDieNnLFaCK4xUVstkWAKLqPxs"` N string `json:"n" example:"oBcXcJUR-Sb8_b4qIj28LRAPxdF_6odRr52K5-ymiEkR2DOlEuXBtM-biWxPESW-U-zhfHzdVLf6ioy5xL0bJTh8BMIorkrDliN3vb81jCvyOMgZ7ATMJpMAQMmSDN7sL3U45r22FaoQufCJMQHmUsZPecdQSgj2aFBiRXxsLleYlSezdBVT_gKH-coqeYXSC_hk-ezSq4aDZ10BlDnZ-FA7-ES3T7nBmJEAU7KDAGeSvbYAfYimOW0r-Vc0xQNuwGCfzZtSexKXDbYbNwOVo3SjfCabq-gMfap_owcHbKicGBZu1LDlh7CpkmLQf_kv6GihM2LWFFh6Vwg2cltiwF22EIPlUDtYTkUR0qRkdNJaNkwV5Vv_6r3pzSmu5ovRriKtlrvJMjlTnLb4_ltsge3fw5Z34cJrsp094FbUc2O6Or4FGEXUldieJCnVRhs2_h6SDcmeMXs1zfvE5GlDnq8tZV6WMJ5Sb4jNO7rs_hTkr23_E6mVg-DdtozGfqzRzhIjPym6D_jVfR6dZv5W0sKwOHRmT7nYq-C7b2sAwmNNII296M4Rq-jn0b5pgSeMDYbIpbIA4thU8LYU0lBZp_ZVwWKG1RFZDxz3k9O5UVth2kTpTWlwn0hB1aAvgXHo6in1CScITGA72p73RbDieNnLFaCK4xUVstkWAKLqPxs"`
Use string `json:"use" example:"sig"` Use string `json:"use" example:"sig"`
} }
} }

View File

@ -2,11 +2,13 @@ package main
import ( import (
"context" "context"
"encoding/base64"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
"strings"
"github.com/zoriya/kyoo/keibi/dbc" "github.com/zoriya/kyoo/keibi/dbc"
_ "github.com/zoriya/kyoo/keibi/docs" _ "github.com/zoriya/kyoo/keibi/docs"
@ -123,6 +125,30 @@ type Handler struct {
config *Configuration config *Configuration
} }
func (h *Handler) TokenToJwt(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
auth := c.Request().Header.Get("Authorization")
if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
return next(c)
}
token := auth[len("Bearer "):]
// this is only used to check if it is a session token or a jwt
_, err := base64.RawURLEncoding.DecodeString(token)
if err != nil {
return next(c)
}
jwt, err := h.createJwt(token)
if err != nil {
return err
}
c.Request().Header.Set("Authorization", jwt)
return next(c)
}
}
// @title Keibi - Kyoo's auth // @title Keibi - Kyoo's auth
// @version 1.0 // @version 1.0
// @description Auth system made for kyoo. // @description Auth system made for kyoo.
@ -167,6 +193,7 @@ func main() {
g := e.Group(conf.Prefix) g := e.Group(conf.Prefix)
r := e.Group(conf.Prefix) r := e.Group(conf.Prefix)
r.Use(h.TokenToJwt)
r.Use(echojwt.WithConfig(echojwt.Config{ r.Use(echojwt.WithConfig(echojwt.Config{
SigningMethod: "RS256", SigningMethod: "RS256",
SigningKey: h.config.JwtPublicKey, SigningKey: h.config.JwtPublicKey,

View File

@ -118,7 +118,7 @@ func (h *Handler) createSession(c echo.Context, user *User) error {
} }
session, err := h.db.CreateSession(ctx, dbc.CreateSessionParams{ session, err := h.db.CreateSession(ctx, dbc.CreateSessionParams{
Token: base64.StdEncoding.EncodeToString(id), Token: base64.RawURLEncoding.EncodeToString(id),
UserPk: user.Pk, UserPk: user.Pk,
Device: device, Device: device,
}) })