Merge pull request 'sqlc removed and adding sessionToken to jwt' (#9) from features/sessiontokens into main
Reviewed-on: #9
This commit is contained in:
commit
877a6a9619
@ -60,7 +60,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/articles/by/sourceid": {
|
||||
"/v1/articles/by/sourceId": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@ -1035,7 +1035,7 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/users/refreshToken": {
|
||||
"/v1/users/refresh/token": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@ -1350,9 +1350,6 @@ const docTemplate = `{
|
||||
"refreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -51,7 +51,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/articles/by/sourceid": {
|
||||
"/v1/articles/by/sourceId": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
@ -1026,7 +1026,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/users/refreshToken": {
|
||||
"/v1/users/refresh/token": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
@ -1341,9 +1341,6 @@
|
||||
"refreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"sessionToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -84,8 +84,6 @@ definitions:
|
||||
type: string
|
||||
refreshToken:
|
||||
type: string
|
||||
sessionToken:
|
||||
type: string
|
||||
token:
|
||||
type: string
|
||||
type:
|
||||
@ -221,7 +219,7 @@ paths:
|
||||
summary: Returns an article and source based on defined ID.
|
||||
tags:
|
||||
- Articles
|
||||
/v1/articles/by/sourceid:
|
||||
/v1/articles/by/sourceId:
|
||||
get:
|
||||
parameters:
|
||||
- description: source id
|
||||
@ -776,7 +774,7 @@ paths:
|
||||
summary: Revokes the current session token and replaces it with a new one.
|
||||
tags:
|
||||
- Users
|
||||
/v1/users/refreshToken:
|
||||
/v1/users/refresh/token:
|
||||
post:
|
||||
parameters:
|
||||
- description: body
|
||||
|
@ -1,6 +1,5 @@
|
||||
package domain
|
||||
|
||||
|
||||
type BaseResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
@ -10,7 +9,6 @@ type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
Type string `json:"type"`
|
||||
RefreshToken string `json:"refreshToken"`
|
||||
SessionToken string `json:"sessionToken"`
|
||||
}
|
||||
|
||||
type ArticleResponse struct {
|
||||
@ -36,4 +34,4 @@ type DiscordWebhookResponse struct {
|
||||
type SourcesResponse struct {
|
||||
BaseResponse
|
||||
Payload []SourceDto `json:"payload"`
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ func (s *Handler) getArticleDetails(c echo.Context) error {
|
||||
// @Param page query int false "Page to query"
|
||||
// @Produce application/json
|
||||
// @Tags Articles
|
||||
// @Router /v1/articles/by/sourceid [get]
|
||||
// @Router /v1/articles/by/sourceId [get]
|
||||
// @Success 200 {object} domain.ArticleResponse "OK"
|
||||
// @Failure 400 {object} domain.BaseResponse
|
||||
// @Failure 500 {object} domain.BaseResponse
|
||||
|
@ -110,7 +110,8 @@ func NewServer(ctx context.Context, configs services.Configs, conn *sql.DB) *Han
|
||||
users.Use(echojwt.WithConfig(jwtConfig))
|
||||
users.POST("/scopes/add", s.AddScopes)
|
||||
users.POST("/scopes/remove", s.RemoveScopes)
|
||||
users.POST("/refreshToken", s.RefreshJwtToken)
|
||||
users.POST("/refresh/token", s.RefreshJwtToken)
|
||||
users.POST("/refresh/sessionToken", s.NewSessionToken)
|
||||
|
||||
s.Router = router
|
||||
return s
|
||||
@ -161,18 +162,24 @@ func (s *Handler) ValidateJwtToken(c echo.Context, requiredScope string) (JwtTok
|
||||
err = token.hasExpired()
|
||||
if err != nil {
|
||||
return JwtToken{}, errors.New(ErrJwtExpired)
|
||||
//s.WriteMessage(c, ErrJwtExpired, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
err = token.hasScope(requiredScope)
|
||||
if err != nil {
|
||||
return JwtToken{}, errors.New(ErrJwtScopeMissing)
|
||||
//s.WriteMessage(c, ErrJwtScopeMissing, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
if token.Iss != s.config.ServerAddress {
|
||||
return JwtToken{}, errors.New(ErrJwtInvalidIssuer)
|
||||
//s.WriteMessage(c, ErrJwtInvalidIssuer, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
user, err := s.repo.Users.GetUser(c.Request().Context(), token.UserName)
|
||||
if err != nil {
|
||||
return JwtToken{}, errors.New("user record not found")
|
||||
}
|
||||
|
||||
if user.SessionToken != token.SessionToken {
|
||||
return JwtToken{}, errors.New("invalid session token")
|
||||
}
|
||||
|
||||
return token, nil
|
||||
|
@ -19,12 +19,13 @@ const (
|
||||
)
|
||||
|
||||
type JwtToken struct {
|
||||
Exp time.Time `json:"exp"`
|
||||
Iss string `json:"iss"`
|
||||
Authorized bool `json:"authorized"`
|
||||
UserName string `json:"username"`
|
||||
UserId int64 `json:"userId"`
|
||||
Scopes []string `json:"scopes"`
|
||||
Exp time.Time `json:"exp"`
|
||||
Iss string `json:"iss"`
|
||||
Authorized bool `json:"authorized"`
|
||||
UserName string `json:"username"`
|
||||
UserId int64 `json:"userId"`
|
||||
Scopes []string `json:"scopes"`
|
||||
SessionToken string `json:"sessionToken"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ func (h *Handler) AuthRegister(c echo.Context) error {
|
||||
return h.WriteError(c, err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
_, err = h.repo.Users.Create(c.Request().Context(), username, password, "", domain.ScopeArticleRead)
|
||||
_, err = h.repo.Users.Create(c.Request().Context(), username, password, domain.ScopeArticleRead)
|
||||
if err != nil {
|
||||
return h.InternalServerErrorResponse(c, err.Error())
|
||||
}
|
||||
@ -92,12 +92,8 @@ func (h *Handler) AuthLogin(c echo.Context) error {
|
||||
// TODO think about moving this down some?
|
||||
expiresAt := time.Now().Add(time.Hour * 48)
|
||||
userScopes := strings.Split(user.Scopes, ",")
|
||||
sessionToken, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
return h.InternalServerErrorResponse(c, err.Error())
|
||||
}
|
||||
|
||||
jwt, err := h.generateJwtWithExp(username, h.config.ServerAddress, sessionToken.String(), userScopes, user.ID, expiresAt)
|
||||
jwt, err := h.generateJwtWithExp(username, h.config.ServerAddress, user.SessionToken, userScopes, user.ID, expiresAt)
|
||||
if err != nil {
|
||||
return h.InternalServerErrorResponse(c, err.Error())
|
||||
}
|
||||
@ -114,7 +110,6 @@ func (h *Handler) AuthLogin(c echo.Context) error {
|
||||
Token: jwt,
|
||||
Type: "Bearer",
|
||||
RefreshToken: refresh,
|
||||
SessionToken: sessionToken.String(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -152,7 +147,7 @@ func (h *Handler) createAdminToken(c echo.Context, password string) error {
|
||||
// This will take collect some information about the requested refresh, validate and then return a new jwt token if approved.
|
||||
// Register
|
||||
// @Summary Generates a new token
|
||||
// @Router /v1/users/refreshToken [post]
|
||||
// @Router /v1/users/refresh/token [post]
|
||||
// @Param request body domain.RefreshTokenRequest true "body"
|
||||
// @Tags Users
|
||||
// @Success 200 {object} domain.LoginResponse
|
||||
@ -183,7 +178,7 @@ func (h *Handler) RefreshJwtToken(c echo.Context) error {
|
||||
}
|
||||
userScopes := strings.Split(user.Scopes, ",")
|
||||
|
||||
jwt, err := h.generateJwtWithExp(request.Username, h.config.ServerAddress, "", userScopes, user.ID, time.Now().Add(time.Hour*48))
|
||||
jwt, err := h.generateJwtWithExp(request.Username, h.config.ServerAddress, user.SessionToken, userScopes, user.ID, time.Now().Add(time.Hour*48))
|
||||
if err != nil {
|
||||
return h.InternalServerErrorResponse(c, err.Error())
|
||||
}
|
||||
@ -281,16 +276,18 @@ func (h *Handler) RemoveScopes(c echo.Context) error {
|
||||
// @Failure 400 {object} domain.BaseResponse
|
||||
// @Failure 500 {object} domain.BaseResponse
|
||||
// @Security Bearer
|
||||
func (h *Handler) LogoutEverywhere(c echo.Context) error {
|
||||
func (h *Handler) NewSessionToken(c echo.Context) error {
|
||||
token, err := h.getJwtTokenFromContext(c)
|
||||
if err != nil {
|
||||
return h.WriteError(c, err, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
err = token.IsValid(domain.ScopeAll)
|
||||
_, err = h.repo.Users.NewSessionToken(c.Request().Context(), token.UserName)
|
||||
if err != nil {
|
||||
return h.WriteError(c, err, http.StatusUnauthorized)
|
||||
return h.WriteError(c, err, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return c.String(http.StatusInternalServerError, "Not Implemented")
|
||||
return c.JSON(http.StatusInternalServerError, domain.BaseResponse{
|
||||
Message: "OK",
|
||||
})
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ type UserServices interface {
|
||||
GetUser(ctx context.Context, username string) (entity.UserEntity, error)
|
||||
AddScopes(ctx context.Context, username string, scopes []string) error
|
||||
RemoveScopes(ctx context.Context, username string, scopes []string) error
|
||||
Create(ctx context.Context, name, password, sessionToken, scope string) (entity.UserEntity, error)
|
||||
NewSessionToken(ctx context.Context, name string) error
|
||||
Create(ctx context.Context, name, password, scope string) (entity.UserEntity, error)
|
||||
NewSessionToken(ctx context.Context, name string) (string, error)
|
||||
CheckPasswordForRequirements(password string) error
|
||||
}
|
||||
|
||||
@ -128,32 +128,37 @@ func (us UserService) doesScopeExist(scopes []string, target string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (us UserService) Create(ctx context.Context, name, password, sessionToken, scope string) (entity.UserEntity, error) {
|
||||
func (us UserService) Create(ctx context.Context, name, password, scope string) (entity.UserEntity, error) {
|
||||
err := us.CheckPasswordForRequirements(password)
|
||||
if err != nil {
|
||||
return entity.UserEntity{}, err
|
||||
}
|
||||
|
||||
us.repo.Create(ctx, name, password, sessionToken, domain.ScopeArticleRead)
|
||||
token, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
return entity.UserEntity{}, err
|
||||
}
|
||||
|
||||
us.repo.Create(ctx, name, password, token.String(), domain.ScopeArticleRead)
|
||||
return entity.UserEntity{}, nil
|
||||
}
|
||||
|
||||
func (us UserService) NewSessionToken(ctx context.Context, name string) error {
|
||||
func (us UserService) NewSessionToken(ctx context.Context, name string) (string, error) {
|
||||
token, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
rows, err := us.repo.UpdateSessionToken(ctx, name, token.String())
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if rows != 1 {
|
||||
return fmt.Errorf("UserService.NewSessionToken %w", err)
|
||||
return "", fmt.Errorf("UserService.NewSessionToken %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return token.String(), nil
|
||||
}
|
||||
|
||||
func (us UserService) CheckPasswordForRequirements(password string) error {
|
||||
|
Loading…
Reference in New Issue
Block a user