From cc0caf2ab036bbb8ea253ac086b44e770013adb2 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 16 Nov 2024 18:04:33 +0300 Subject: [PATCH] Another bunch of improvements --- .../AuthorizedRule.go | 0 .../IsAdminRule.go | 0 .../IsOwnerOfTheBlogRule.go | 0 .../IsOwnerOfThePostRule.go | 0 .../postPolicy.go | 2 +- .../postRules/createRule.go | 2 +- .../postRules/deleteRule.go | 2 +- .../postRules/readRule.go | 0 .../postRules/updateRule.go | 3 +- .../ABAC/ProfilePolicies/ProfilePolicies.go | 31 ++++++++++++ .../ProfilesRules/UpdateRule.go | 22 +++++++++ .../blogsPolicies/blogRules/createRule.go | 2 +- .../blogsPolicies/blogRules/deleteRule.go | 2 +- .../blogsPolicies/blogRules/updateRule.go | 2 +- enshi_back/db/go_queries/blogs_queries.sql.go | 4 +- enshi_back/db/go_queries/models.go | 2 +- enshi_back/db/sqlc.yml | 3 ++ enshi_back/middleware/ProfileMiddleware.go | 40 ++++++++++++++++ enshi_back/middleware/postsMiddleware.go | 2 +- enshi_back/routes/blogRoutes/createBlog.go | 48 +++++++++++++++++++ enshi_back/routes/routesSetup.go | 21 ++++++-- .../userProfileRoutes/updateUserProfile.go | 6 ++- enshi_back/utils/GetContextPayload.go | 21 ++++++++ enshi_back/utils/uuidGenerator.go | 18 +++++++ 24 files changed, 215 insertions(+), 18 deletions(-) rename enshi_back/ABAC/{globalRules => GlobalRules}/AuthorizedRule.go (100%) rename enshi_back/ABAC/{globalRules => GlobalRules}/IsAdminRule.go (100%) rename enshi_back/ABAC/{globalRules => GlobalRules}/IsOwnerOfTheBlogRule.go (100%) rename enshi_back/ABAC/{globalRules => GlobalRules}/IsOwnerOfThePostRule.go (100%) rename enshi_back/ABAC/{postsPolicies => PostsPolicies}/postPolicy.go (93%) rename enshi_back/ABAC/{postsPolicies => PostsPolicies}/postRules/createRule.go (90%) rename enshi_back/ABAC/{postsPolicies => PostsPolicies}/postRules/deleteRule.go (92%) rename enshi_back/ABAC/{postsPolicies => PostsPolicies}/postRules/readRule.go (100%) rename enshi_back/ABAC/{postsPolicies => PostsPolicies}/postRules/updateRule.go (83%) create mode 100644 enshi_back/ABAC/ProfilePolicies/ProfilePolicies.go create mode 100644 enshi_back/ABAC/ProfilePolicies/ProfilesRules/UpdateRule.go create mode 100644 enshi_back/middleware/ProfileMiddleware.go create mode 100644 enshi_back/routes/blogRoutes/createBlog.go create mode 100644 enshi_back/utils/GetContextPayload.go create mode 100644 enshi_back/utils/uuidGenerator.go diff --git a/enshi_back/ABAC/globalRules/AuthorizedRule.go b/enshi_back/ABAC/GlobalRules/AuthorizedRule.go similarity index 100% rename from enshi_back/ABAC/globalRules/AuthorizedRule.go rename to enshi_back/ABAC/GlobalRules/AuthorizedRule.go diff --git a/enshi_back/ABAC/globalRules/IsAdminRule.go b/enshi_back/ABAC/GlobalRules/IsAdminRule.go similarity index 100% rename from enshi_back/ABAC/globalRules/IsAdminRule.go rename to enshi_back/ABAC/GlobalRules/IsAdminRule.go diff --git a/enshi_back/ABAC/globalRules/IsOwnerOfTheBlogRule.go b/enshi_back/ABAC/GlobalRules/IsOwnerOfTheBlogRule.go similarity index 100% rename from enshi_back/ABAC/globalRules/IsOwnerOfTheBlogRule.go rename to enshi_back/ABAC/GlobalRules/IsOwnerOfTheBlogRule.go diff --git a/enshi_back/ABAC/globalRules/IsOwnerOfThePostRule.go b/enshi_back/ABAC/GlobalRules/IsOwnerOfThePostRule.go similarity index 100% rename from enshi_back/ABAC/globalRules/IsOwnerOfThePostRule.go rename to enshi_back/ABAC/GlobalRules/IsOwnerOfThePostRule.go diff --git a/enshi_back/ABAC/postsPolicies/postPolicy.go b/enshi_back/ABAC/PostsPolicies/postPolicy.go similarity index 93% rename from enshi_back/ABAC/postsPolicies/postPolicy.go rename to enshi_back/ABAC/PostsPolicies/postPolicy.go index d4bb86d..0d5415f 100644 --- a/enshi_back/ABAC/postsPolicies/postPolicy.go +++ b/enshi_back/ABAC/PostsPolicies/postPolicy.go @@ -1,7 +1,7 @@ package postspolicies import ( - postRules "enshi/ABAC/postsPolicies/postRules" + "enshi/ABAC/PostsPolicies/postRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" diff --git a/enshi_back/ABAC/postsPolicies/postRules/createRule.go b/enshi_back/ABAC/PostsPolicies/postRules/createRule.go similarity index 90% rename from enshi_back/ABAC/postsPolicies/postRules/createRule.go rename to enshi_back/ABAC/PostsPolicies/postRules/createRule.go index 1745c19..b998d5c 100644 --- a/enshi_back/ABAC/postsPolicies/postRules/createRule.go +++ b/enshi_back/ABAC/PostsPolicies/postRules/createRule.go @@ -1,7 +1,7 @@ package postRules import ( - globalrules "enshi/ABAC/globalRules" + globalrules "enshi/ABAC/GlobalRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" diff --git a/enshi_back/ABAC/postsPolicies/postRules/deleteRule.go b/enshi_back/ABAC/PostsPolicies/postRules/deleteRule.go similarity index 92% rename from enshi_back/ABAC/postsPolicies/postRules/deleteRule.go rename to enshi_back/ABAC/PostsPolicies/postRules/deleteRule.go index fb3aecc..1e71cb6 100644 --- a/enshi_back/ABAC/postsPolicies/postRules/deleteRule.go +++ b/enshi_back/ABAC/PostsPolicies/postRules/deleteRule.go @@ -1,7 +1,7 @@ package postRules import ( - globalrules "enshi/ABAC/globalRules" + globalrules "enshi/ABAC/GlobalRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" diff --git a/enshi_back/ABAC/postsPolicies/postRules/readRule.go b/enshi_back/ABAC/PostsPolicies/postRules/readRule.go similarity index 100% rename from enshi_back/ABAC/postsPolicies/postRules/readRule.go rename to enshi_back/ABAC/PostsPolicies/postRules/readRule.go diff --git a/enshi_back/ABAC/postsPolicies/postRules/updateRule.go b/enshi_back/ABAC/PostsPolicies/postRules/updateRule.go similarity index 83% rename from enshi_back/ABAC/postsPolicies/postRules/updateRule.go rename to enshi_back/ABAC/PostsPolicies/postRules/updateRule.go index eabb5b9..44cd7b6 100644 --- a/enshi_back/ABAC/postsPolicies/postRules/updateRule.go +++ b/enshi_back/ABAC/PostsPolicies/postRules/updateRule.go @@ -1,7 +1,7 @@ package postRules import ( - globalrules "enshi/ABAC/globalRules" + globalrules "enshi/ABAC/GlobalRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" @@ -11,7 +11,6 @@ import ( func PostUpdateRule(c *gin.Context) (bool, []error) { rulesToCheck := []rules.RuleFunction{ globalrules.AuthorizedRule, - globalrules.IsOwnerOfThePostRule, } isAllowed, errors := rules.CheckRules( diff --git a/enshi_back/ABAC/ProfilePolicies/ProfilePolicies.go b/enshi_back/ABAC/ProfilePolicies/ProfilePolicies.go new file mode 100644 index 0000000..cee74e1 --- /dev/null +++ b/enshi_back/ABAC/ProfilePolicies/ProfilePolicies.go @@ -0,0 +1,31 @@ +package profilepolicies + +import ( + profilesrules "enshi/ABAC/ProfilePolicies/ProfilesRules" + "enshi/ABAC/rules" + + "github.com/gin-gonic/gin" +) + +const ( + RESET_PROFILE = "reset_profile" + UPDATE_PROFILE = "update_profile" + CREATE_PROFILE = "create_profile" + GET_PROFILE = "get_profile" +) + +func ProfilePolicies(c *gin.Context) (bool, []error) { + target, exists := c.Get("target") + if !exists { + return false, nil + } + + // Permit if one permit + switch target { + case UPDATE_PROFILE: + return rules.CheckRule(c, profilesrules.UpdateProfileRule) + + } + + return false, nil +} diff --git a/enshi_back/ABAC/ProfilePolicies/ProfilesRules/UpdateRule.go b/enshi_back/ABAC/ProfilePolicies/ProfilesRules/UpdateRule.go new file mode 100644 index 0000000..f90f857 --- /dev/null +++ b/enshi_back/ABAC/ProfilePolicies/ProfilesRules/UpdateRule.go @@ -0,0 +1,22 @@ +package profilesrules + +import ( + globalrules "enshi/ABAC/GlobalRules" + "enshi/ABAC/rules" + + "github.com/gin-gonic/gin" +) + +func UpdateProfileRule(c *gin.Context) (bool, []error) { + rulesToCheck := []rules.RuleFunction{ + globalrules.AuthorizedRule, + } + + isAllowed, errors := rules.CheckRules( + c, + rulesToCheck, + rules.ALL_RULES_MUST_BE_COMPLETED, + ) + + return isAllowed, errors +} diff --git a/enshi_back/ABAC/blogsPolicies/blogRules/createRule.go b/enshi_back/ABAC/blogsPolicies/blogRules/createRule.go index 8c25f3c..c973353 100644 --- a/enshi_back/ABAC/blogsPolicies/blogRules/createRule.go +++ b/enshi_back/ABAC/blogsPolicies/blogRules/createRule.go @@ -1,7 +1,7 @@ package blogrules import ( - globalrules "enshi/ABAC/globalRules" + globalrules "enshi/ABAC/GlobalRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" diff --git a/enshi_back/ABAC/blogsPolicies/blogRules/deleteRule.go b/enshi_back/ABAC/blogsPolicies/blogRules/deleteRule.go index 49b7f01..5c4f024 100644 --- a/enshi_back/ABAC/blogsPolicies/blogRules/deleteRule.go +++ b/enshi_back/ABAC/blogsPolicies/blogRules/deleteRule.go @@ -1,7 +1,7 @@ package blogrules import ( - globalrules "enshi/ABAC/globalRules" + globalrules "enshi/ABAC/GlobalRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" diff --git a/enshi_back/ABAC/blogsPolicies/blogRules/updateRule.go b/enshi_back/ABAC/blogsPolicies/blogRules/updateRule.go index 8371955..cb6ab72 100644 --- a/enshi_back/ABAC/blogsPolicies/blogRules/updateRule.go +++ b/enshi_back/ABAC/blogsPolicies/blogRules/updateRule.go @@ -1,7 +1,7 @@ package blogrules import ( - globalrules "enshi/ABAC/globalRules" + globalrules "enshi/ABAC/GlobalRules" "enshi/ABAC/rules" "github.com/gin-gonic/gin" diff --git a/enshi_back/db/go_queries/blogs_queries.sql.go b/enshi_back/db/go_queries/blogs_queries.sql.go index fc040cf..3029ce9 100644 --- a/enshi_back/db/go_queries/blogs_queries.sql.go +++ b/enshi_back/db/go_queries/blogs_queries.sql.go @@ -21,7 +21,7 @@ RETURNING blog_id, user_id, title, description, category_id, created_at type CreateBlogByUserIdParams struct { BlogID int64 `json:"blog_id"` UserID int64 `json:"user_id"` - Title pgtype.Text `json:"title"` + Title pgtype.Text `json:"title" validate:"required"` Description pgtype.Text `json:"description"` CategoryID pgtype.Int4 `json:"category_id"` } @@ -117,7 +117,7 @@ RETURNING blog_id, user_id, title, description, category_id, created_at ` type UpdateBlogInfoByBlogIdParams struct { - Title pgtype.Text `json:"title"` + Title pgtype.Text `json:"title" validate:"required"` Description pgtype.Text `json:"description"` CategoryID pgtype.Int4 `json:"category_id"` BlogID int64 `json:"blog_id"` diff --git a/enshi_back/db/go_queries/models.go b/enshi_back/db/go_queries/models.go index 7d227a9..6438133 100644 --- a/enshi_back/db/go_queries/models.go +++ b/enshi_back/db/go_queries/models.go @@ -11,7 +11,7 @@ import ( type Blog struct { BlogID int64 `json:"blog_id"` UserID int64 `json:"user_id"` - Title pgtype.Text `json:"title"` + Title pgtype.Text `json:"title" validate:"required"` Description pgtype.Text `json:"description"` CategoryID pgtype.Int4 `json:"category_id"` CreatedAt pgtype.Timestamp `json:"created_at"` diff --git a/enshi_back/db/sqlc.yml b/enshi_back/db/sqlc.yml index cdfcea3..1eb5d5f 100644 --- a/enshi_back/db/sqlc.yml +++ b/enshi_back/db/sqlc.yml @@ -18,6 +18,9 @@ sql: - column: users.email go_struct_tag: validate:"required,email" + - column: blogs.title + go_struct_tag: validate:"required" + - db_type: "uuid" go_type: import: 'github.com/google/uuid' diff --git a/enshi_back/middleware/ProfileMiddleware.go b/enshi_back/middleware/ProfileMiddleware.go new file mode 100644 index 0000000..494b09c --- /dev/null +++ b/enshi_back/middleware/ProfileMiddleware.go @@ -0,0 +1,40 @@ +package middleware + +import ( + profilepolicies "enshi/ABAC/ProfilePolicies" + rest_api_stuff "enshi/REST_API_stuff" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" +) + +func ProfileMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + switch c.Request.Method { + case "PUT": + c.Set("target", profilepolicies.UPDATE_PROFILE) + } + + isAllowed, errors := profilepolicies.ProfilePolicies(c) + + var errorsMap = map[int]string{} + for i, error := range errors { + errorsMap[i] = error.Error() + } + + if errors != nil { + c.IndentedJSON(http.StatusUnauthorized, errorsMap) + c.Abort() + return + } + + if !isAllowed { + rest_api_stuff.UnauthorizedAnswer(c, fmt.Errorf("you have no permission")) + c.Abort() + return + } + + c.Next() + } +} diff --git a/enshi_back/middleware/postsMiddleware.go b/enshi_back/middleware/postsMiddleware.go index 9f3c911..2dc90fa 100644 --- a/enshi_back/middleware/postsMiddleware.go +++ b/enshi_back/middleware/postsMiddleware.go @@ -1,7 +1,7 @@ package middleware import ( - postspolicies "enshi/ABAC/postsPolicies" + postspolicies "enshi/ABAC/PostsPolicies" rest_api_stuff "enshi/REST_API_stuff" "fmt" "net/http" diff --git a/enshi_back/routes/blogRoutes/createBlog.go b/enshi_back/routes/blogRoutes/createBlog.go new file mode 100644 index 0000000..ecb1e2f --- /dev/null +++ b/enshi_back/routes/blogRoutes/createBlog.go @@ -0,0 +1,48 @@ +package blogRoutes + +import ( + "context" + rest_api_stuff "enshi/REST_API_stuff" + db_repo "enshi/db/go_queries" + "enshi/db_connection" + "enshi/middleware/getters" + "enshi/utils" + + "github.com/gin-gonic/gin" +) + +func CreateBlog(c *gin.Context) { + blogParams, err := utils.GetContextPayload[db_repo.CreateBlogByUserIdParams](c) + if err != nil { + rest_api_stuff.BadRequestAnswer(c, err) + return + } + + userId, err := getters.GetUserIdFromContext(c) + if err != nil { + rest_api_stuff.BadRequestAnswer(c, err) + return + } + + blogId, err := utils.GetUUIDv7AsInt64() + if err != nil { + rest_api_stuff.InternalErrorAnswer(c, err) + return + } + + blogParams.UserID = userId + blogParams.BlogID = blogId + + _, err = db_repo. + New(db_connection.Dbx). + CreateBlogByUserId( + context.Background(), + blogParams, + ) + if err != nil { + rest_api_stuff.InternalErrorAnswer(c, err) + return + } + + rest_api_stuff.OkAnswer(c, "blog has been created") +} diff --git a/enshi_back/routes/routesSetup.go b/enshi_back/routes/routesSetup.go index f2c9f4c..6662770 100644 --- a/enshi_back/routes/routesSetup.go +++ b/enshi_back/routes/routesSetup.go @@ -3,6 +3,7 @@ package routes import ( "enshi/middleware" "enshi/routes/authRoutes" + "enshi/routes/blogRoutes" "enshi/routes/postsRoutes" "enshi/routes/userProfileRoutes" "net/http" @@ -57,13 +58,25 @@ func SetupRotes(g *gin.Engine) error { postsRoutes.DeletePost, ) + blogGroup := g.Group("/") + blogGroup.Use(middleware.BlogsMiddleware()) + + blogGroup.POST( + "blogs", + blogRoutes.CreateBlog, + ) + + profilesGroup := g.Group("/") + profilesGroup.Use(middleware.ProfileMiddleware()) + + profilesGroup.PUT( + "profiles", + userProfileRoutes.UpdateUserProfile, + ) + // Auth group routes authGroup := g.Group("/") authGroup.Use(middleware.AuthMiddleware()) - authGroup.PUT( - "user-profiles", - userProfileRoutes.UpdateUserProfile, - ) // Admin group routes adminGroup := authGroup.Group("/admin/") diff --git a/enshi_back/routes/userProfileRoutes/updateUserProfile.go b/enshi_back/routes/userProfileRoutes/updateUserProfile.go index fe792e9..22f04e7 100644 --- a/enshi_back/routes/userProfileRoutes/updateUserProfile.go +++ b/enshi_back/routes/userProfileRoutes/updateUserProfile.go @@ -6,14 +6,16 @@ import ( db_repo "enshi/db/go_queries" "enshi/db_connection" "enshi/middleware/getters" + "enshi/utils" "github.com/gin-gonic/gin" ) func UpdateUserProfile(c *gin.Context) { - var newProfile db_repo.UpdateProfileByUserIdParams + newProfile, err := + utils.GetContextPayload[db_repo.UpdateProfileByUserIdParams](c) - if err := c.BindJSON(&newProfile); err != nil { + if err != nil { rest_api_stuff.BadRequestAnswer(c, err) return } diff --git a/enshi_back/utils/GetContextPayload.go b/enshi_back/utils/GetContextPayload.go new file mode 100644 index 0000000..934207c --- /dev/null +++ b/enshi_back/utils/GetContextPayload.go @@ -0,0 +1,21 @@ +package utils + +import ( + "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" +) + +func GetContextPayload[T any](c *gin.Context) (T, error) { + var params T + + if err := c.BindJSON(¶ms); err != nil { + return params, err + } + + validate := validator.New(validator.WithRequiredStructEnabled()) + if err := validate.Struct(params); err != nil { + return params, err + } + + return params, nil +} diff --git a/enshi_back/utils/uuidGenerator.go b/enshi_back/utils/uuidGenerator.go new file mode 100644 index 0000000..d3f17b9 --- /dev/null +++ b/enshi_back/utils/uuidGenerator.go @@ -0,0 +1,18 @@ +package utils + +import ( + "encoding/binary" + + "github.com/google/uuid" +) + +func GetUUIDv7AsInt64() (int64, error) { + uuid, err := uuid.NewV7() + if err != nil { + return -1, err + } + + return -int64( + binary.BigEndian.Uint64(uuid[8:]), + ), nil +}