From 7d4648e78b39cc6cf76631a9beb2b0714b6c8ae7 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 26 May 2024 09:00:33 -0700 Subject: [PATCH] sqlc removed and adding sessionToken to jwt --- docs/docs.go | 7 ++----- docs/swagger.json | 7 ++----- docs/swagger.yaml | 6 ++---- domain/responses.go | 4 +--- internal/handler/v1/articles.go | 2 +- internal/handler/v1/handler.go | 15 ++++++++++---- internal/handler/v1/jwt.go | 13 ++++++------ internal/handler/v1/users.go | 23 ++++++++++------------ internal/repositoryServices/userService.go | 23 +++++++++++++--------- 9 files changed, 50 insertions(+), 50 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index acb6b6e..1151667 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -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" }, diff --git a/docs/swagger.json b/docs/swagger.json index 56e2d20..2f5f8ae 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -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" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 3076d08..f96541c 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -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 diff --git a/domain/responses.go b/domain/responses.go index fc7c4a3..6fe048e 100644 --- a/domain/responses.go +++ b/domain/responses.go @@ -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"` -} \ No newline at end of file +} diff --git a/internal/handler/v1/articles.go b/internal/handler/v1/articles.go index 73b916a..4b3ce5f 100644 --- a/internal/handler/v1/articles.go +++ b/internal/handler/v1/articles.go @@ -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 diff --git a/internal/handler/v1/handler.go b/internal/handler/v1/handler.go index 671479e..0c86f7a 100644 --- a/internal/handler/v1/handler.go +++ b/internal/handler/v1/handler.go @@ -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 diff --git a/internal/handler/v1/jwt.go b/internal/handler/v1/jwt.go index d234694..12cb26c 100644 --- a/internal/handler/v1/jwt.go +++ b/internal/handler/v1/jwt.go @@ -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 } diff --git a/internal/handler/v1/users.go b/internal/handler/v1/users.go index 8179bbb..2ab3154 100644 --- a/internal/handler/v1/users.go +++ b/internal/handler/v1/users.go @@ -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", + }) } diff --git a/internal/repositoryServices/userService.go b/internal/repositoryServices/userService.go index 4f7acdf..ead3e5c 100644 --- a/internal/repositoryServices/userService.go +++ b/internal/repositoryServices/userService.go @@ -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 {