From 7007cda8f210877e4ac3221d8972eb502e812620 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 22 Jun 2024 13:04:21 +0800 Subject: [PATCH] :recycle: Improve code structure and much easier to read :bug: Fix auth middleware --- .idea/workspace.xml | 95 ++++++++++++------- pkg/hyper/auth_adaptor.go | 2 - pkg/internal/embed.go | 2 +- pkg/internal/server/admin/badges_api.go | 8 +- pkg/internal/server/admin/index.go | 4 +- pkg/internal/server/{ => api}/accounts_api.go | 31 ++++-- pkg/internal/server/{ => api}/auth_api.go | 12 +-- pkg/internal/server/{ => api}/avatar_api.go | 22 +++-- pkg/internal/server/{ => api}/factors_api.go | 2 +- .../server/{ => api}/friendships_api.go | 31 ++++-- pkg/internal/server/api/index.go | 90 ++++++++++++++++++ .../server/{ => api}/notifications_api.go | 33 +++++-- pkg/internal/server/{ => api}/notify_api.go | 6 +- pkg/internal/server/{ => api}/page_api.go | 16 +++- .../server/{ => api}/realm_members_api.go | 28 ++++-- pkg/internal/server/{ => api}/realms_api.go | 32 +++++-- pkg/internal/server/{ => api}/security_api.go | 8 +- pkg/internal/server/{ => api}/userinfo_api.go | 2 +- .../server/{ => api}/well_known_api.go | 2 +- pkg/internal/server/{ => api}/ws.go | 5 +- pkg/internal/server/auth_middleware.go | 55 ----------- pkg/internal/server/exts/auth.go | 53 +++++++++++ pkg/internal/server/exts/cookies.go | 27 ++++++ .../{utils => server/exts}/request.go | 15 +-- pkg/internal/server/server.go | 86 ++--------------- pkg/internal/server/ui/accounts.go | 6 +- pkg/internal/server/ui/index.go | 29 ++---- pkg/internal/server/ui/mfa.go | 12 +-- pkg/internal/server/ui/oauth.go | 16 +++- pkg/internal/server/ui/signin.go | 10 +- pkg/internal/server/ui/signup.go | 6 +- pkg/internal/services/auth.go | 14 +-- pkg/internal/services/jwt.go | 23 ----- pkg/internal/utils/auth.go | 5 - 34 files changed, 451 insertions(+), 337 deletions(-) rename pkg/internal/server/{ => api}/accounts_api.go (86%) rename pkg/internal/server/{ => api}/auth_api.go (93%) rename pkg/internal/server/{ => api}/avatar_api.go (81%) rename pkg/internal/server/{ => api}/factors_api.go (97%) rename pkg/internal/server/{ => api}/friendships_api.go (82%) create mode 100644 pkg/internal/server/api/index.go rename pkg/internal/server/{ => api}/notifications_api.go (79%) rename pkg/internal/server/{ => api}/notify_api.go (93%) rename pkg/internal/server/{ => api}/page_api.go (81%) rename pkg/internal/server/{ => api}/realm_members_api.go (82%) rename pkg/internal/server/{ => api}/realms_api.go (80%) rename pkg/internal/server/{ => api}/security_api.go (81%) rename pkg/internal/server/{ => api}/userinfo_api.go (97%) rename pkg/internal/server/{ => api}/well_known_api.go (98%) rename pkg/internal/server/{ => api}/ws.go (97%) delete mode 100644 pkg/internal/server/auth_middleware.go create mode 100644 pkg/internal/server/exts/auth.go create mode 100644 pkg/internal/server/exts/cookies.go rename pkg/internal/{utils => server/exts}/request.go (65%) delete mode 100644 pkg/internal/utils/auth.go diff --git a/.idea/workspace.xml b/.idea/workspace.xml index cdbf3d5..6876572 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,13 +4,40 @@ - @@ -172,7 +198,8 @@ - true diff --git a/pkg/hyper/auth_adaptor.go b/pkg/hyper/auth_adaptor.go index d224f15..f483560 100644 --- a/pkg/hyper/auth_adaptor.go +++ b/pkg/hyper/auth_adaptor.go @@ -12,7 +12,6 @@ const CookieAtk = "__hydrogen_atk" const CookieRtk = "__hydrogen_rtk" func (v *HyperConn) AuthMiddleware(c *fiber.Ctx) error { - // Detect token var atk string if cookie := c.Cookies(CookieAtk); len(cookie) > 0 { atk = cookie @@ -42,7 +41,6 @@ func (v *HyperConn) AuthMiddleware(c *fiber.Ctx) error { }) } c.Locals("p_user", user) - return nil } return c.Next() diff --git a/pkg/internal/embed.go b/pkg/internal/embed.go index 38dd3ff..7a0136b 100644 --- a/pkg/internal/embed.go +++ b/pkg/internal/embed.go @@ -2,5 +2,5 @@ package pkg import "embed" -//go:embed views/* +//go:embed all:views/* var FS embed.FS diff --git a/pkg/internal/server/admin/badges_api.go b/pkg/internal/server/admin/badges_api.go index bcfdc5b..4c7420a 100644 --- a/pkg/internal/server/admin/badges_api.go +++ b/pkg/internal/server/admin/badges_api.go @@ -2,16 +2,16 @@ package admin import ( "fmt" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) func grantBadge(c *fiber.Ctx) error { - if err := utils.CheckPermissions(c, "AdminGrantBadges", true); err != nil { + if err := exts.EnsureGrantedPerm(c, "AdminGrantBadges", true); err != nil { return err } @@ -21,7 +21,7 @@ func grantBadge(c *fiber.Ctx) error { AccountID uint `json:"account_id"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -44,7 +44,7 @@ func grantBadge(c *fiber.Ctx) error { } func revokeBadge(c *fiber.Ctx) error { - if err := utils.CheckPermissions(c, "AdminRevokeBadges", true); err != nil { + if err := exts.EnsureGrantedPerm(c, "AdminRevokeBadges", true); err != nil { return err } diff --git a/pkg/internal/server/admin/index.go b/pkg/internal/server/admin/index.go index ad11edc..099cb70 100644 --- a/pkg/internal/server/admin/index.go +++ b/pkg/internal/server/admin/index.go @@ -4,8 +4,8 @@ import ( "github.com/gofiber/fiber/v2" ) -func MapAdminEndpoints(A *fiber.App, authMiddleware fiber.Handler) { - admin := A.Group("/api/admin").Use(authMiddleware) +func MapAdminEndpoints(A *fiber.App) { + admin := A.Group("/api/admin") { admin.Post("/badges", grantBadge) admin.Delete("/badges/:badgeId", revokeBadge) diff --git a/pkg/internal/server/accounts_api.go b/pkg/internal/server/api/accounts_api.go similarity index 86% rename from pkg/internal/server/accounts_api.go rename to pkg/internal/server/api/accounts_api.go index 4f64b82..8fbcc84 100644 --- a/pkg/internal/server/accounts_api.go +++ b/pkg/internal/server/api/accounts_api.go @@ -1,12 +1,11 @@ -package server +package api import ( "fmt" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "strconv" "time" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" - "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" @@ -16,7 +15,10 @@ import ( ) func getUserinfo(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var data models.Account if err := database.C. @@ -47,7 +49,10 @@ func getUserinfo(c *fiber.Ctx) error { } func getEvents(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) @@ -76,7 +81,10 @@ func getEvents(c *fiber.Ctx) error { } func editUserinfo(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var data struct { Nick string `json:"nick" validate:"required,min=4,max=24"` @@ -86,7 +94,7 @@ func editUserinfo(c *fiber.Ctx) error { Birthday time.Time `json:"birthday"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -116,7 +124,10 @@ func editUserinfo(c *fiber.Ctx) error { } func killSession(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) id, _ := c.ParamsInt("ticketId", 0) if err := database.C.Delete(&models.AuthTicket{}, &models.AuthTicket{ @@ -138,7 +149,7 @@ func doRegister(c *fiber.Ctx) error { MagicToken string `json:"magic_token"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } else if viper.GetBool("use_registration_magic_token") && len(data.MagicToken) <= 0 { return fmt.Errorf("missing magic token in request") @@ -167,7 +178,7 @@ func doRegisterConfirm(c *fiber.Ctx) error { Code string `json:"code" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } diff --git a/pkg/internal/server/auth_api.go b/pkg/internal/server/api/auth_api.go similarity index 93% rename from pkg/internal/server/auth_api.go rename to pkg/internal/server/api/auth_api.go index 82722bd..4c8b24c 100644 --- a/pkg/internal/server/auth_api.go +++ b/pkg/internal/server/api/auth_api.go @@ -1,8 +1,8 @@ -package server +package api import ( "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "time" "github.com/gofiber/fiber/v2" @@ -16,7 +16,7 @@ func doAuthenticate(c *fiber.Ctx) error { Password string `json:"password" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -48,7 +48,7 @@ func doMultiFactorAuthenticate(c *fiber.Ctx) error { Code string `json:"code" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -85,7 +85,7 @@ func getToken(c *fiber.Ctx) error { GrantType string `json:"grant_type" form:"grant_type"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -134,7 +134,7 @@ func getToken(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "unsupported exchange token type") } - services.SetJwtCookieSet(c, access, refresh) + exts.SetAuthCookies(c, access, refresh) return c.JSON(fiber.Map{ "id_token": access, diff --git a/pkg/internal/server/avatar_api.go b/pkg/internal/server/api/avatar_api.go similarity index 81% rename from pkg/internal/server/avatar_api.go rename to pkg/internal/server/api/avatar_api.go index 8d1ce69..a650ad9 100644 --- a/pkg/internal/server/avatar_api.go +++ b/pkg/internal/server/api/avatar_api.go @@ -1,4 +1,4 @@ -package server +package api import ( "context" @@ -7,20 +7,27 @@ import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/gap" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" "github.com/samber/lo" ) func setAvatar(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) + + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } var data struct { AttachmentID uint `json:"attachment" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -47,13 +54,16 @@ func setAvatar(c *fiber.Ctx) error { } func setBanner(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var data struct { AttachmentID uint `json:"attachment" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } diff --git a/pkg/internal/server/factors_api.go b/pkg/internal/server/api/factors_api.go similarity index 97% rename from pkg/internal/server/factors_api.go rename to pkg/internal/server/api/factors_api.go index 2bff580..98a7c46 100644 --- a/pkg/internal/server/factors_api.go +++ b/pkg/internal/server/api/factors_api.go @@ -1,4 +1,4 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/services" diff --git a/pkg/internal/server/friendships_api.go b/pkg/internal/server/api/friendships_api.go similarity index 82% rename from pkg/internal/server/friendships_api.go rename to pkg/internal/server/api/friendships_api.go index b7a87fb..d68482f 100644 --- a/pkg/internal/server/friendships_api.go +++ b/pkg/internal/server/api/friendships_api.go @@ -1,14 +1,17 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) func listFriendship(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) status := c.QueryInt("status", -1) var err error @@ -27,7 +30,10 @@ func listFriendship(c *fiber.Ctx) error { } func getFriendship(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) relatedId, _ := c.ParamsInt("relatedId", 0) related, err := services.GetAccount(uint(relatedId)) @@ -43,7 +49,10 @@ func getFriendship(c *fiber.Ctx) error { } func makeFriendship(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) relatedName := c.Query("related") relatedId, _ := c.ParamsInt("relatedId", 0) @@ -72,14 +81,17 @@ func makeFriendship(c *fiber.Ctx) error { } func editFriendship(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) relatedId, _ := c.ParamsInt("relatedId", 0) var data struct { Status uint8 `json:"status"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } @@ -103,7 +115,10 @@ func editFriendship(c *fiber.Ctx) error { } func deleteFriendship(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) relatedId, _ := c.ParamsInt("relatedId", 0) related, err := services.GetAccount(uint(relatedId)) diff --git a/pkg/internal/server/api/index.go b/pkg/internal/server/api/index.go new file mode 100644 index 0000000..64760a3 --- /dev/null +++ b/pkg/internal/server/api/index.go @@ -0,0 +1,90 @@ +package api + +import ( + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" + "github.com/gofiber/contrib/websocket" + "github.com/gofiber/fiber/v2" +) + +func MapAPIs(app *fiber.App) { + app.Get("/.well-known", getMetadata) + app.Get("/.well-known/openid-configuration", getOidcConfiguration) + + api := app.Group("/api").Name("API") + { + notify := api.Group("/notifications").Name("Notifications API") + { + notify.Get("/", getNotifications) + notify.Post("/subscribe", addNotifySubscriber) + notify.Put("/batch/read", markNotificationReadBatch) + notify.Put("/:notificationId/read", markNotificationRead) + } + + me := api.Group("/users/me").Name("Myself Operations") + { + + me.Put("/avatar", setAvatar) + me.Put("/banner", setBanner) + + me.Get("/", getUserinfo) + me.Get("/page", getOwnPersonalPage) + me.Put("/", editUserinfo) + me.Put("/page", editPersonalPage) + me.Get("/events", getEvents) + me.Get("/tickets", getTickets) + me.Delete("/tickets/:ticketId", killSession) + + me.Post("/confirm", doRegisterConfirm) + + friends := me.Group("/friends").Name("Friends") + { + friends.Get("/", listFriendship) + friends.Get("/:relatedId", getFriendship) + friends.Post("/", makeFriendship) + friends.Post("/:relatedId", makeFriendship) + friends.Put("/:relatedId", editFriendship) + friends.Delete("/:relatedId", deleteFriendship) + } + } + + directory := api.Group("/users/:alias").Name("User Directory") + { + directory.Get("/", getOtherUserinfo) + directory.Get("/page", getPersonalPage) + } + + api.Post("/users", doRegister) + + api.Post("/auth", doAuthenticate) + api.Post("/auth/token", getToken) + api.Post("/auth/factors/:factorId", requestFactorToken) + + realms := api.Group("/realms").Name("Realms API") + { + realms.Get("/", listCommunityRealm) + realms.Get("/me", listOwnedRealm) + realms.Get("/me/available", listAvailableRealm) + realms.Get("/:realm", getRealm) + realms.Get("/:realm/members", listRealmMembers) + realms.Get("/:realm/members/me", getMyRealmMember) + realms.Post("/", createRealm) + realms.Put("/:realmId", editRealm) + realms.Delete("/:realmId", deleteRealm) + realms.Post("/:realm/members", addRealmMember) + realms.Delete("/:realm/members", removeRealmMember) + realms.Delete("/:realm/members/me", leaveRealm) + } + + developers := api.Group("/dev").Name("Developers API") + { + developers.Post("/notify", notifyUser) + } + + api.Use(func(c *fiber.Ctx) error { + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + return c.Next() + }).Get("/ws", websocket.New(listenWebsocket)) + } +} diff --git a/pkg/internal/server/notifications_api.go b/pkg/internal/server/api/notifications_api.go similarity index 79% rename from pkg/internal/server/notifications_api.go rename to pkg/internal/server/api/notifications_api.go index b6ccc14..9c2bf6f 100644 --- a/pkg/internal/server/notifications_api.go +++ b/pkg/internal/server/api/notifications_api.go @@ -1,18 +1,22 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) func getNotifications(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) + tx := database.C.Where(&models.Notification{RecipientID: user.ID}).Model(&models.Notification{}) var count int64 @@ -36,9 +40,16 @@ func getNotifications(c *fiber.Ctx) error { } func markNotificationRead(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) id, _ := c.ParamsInt("notificationId", 0) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + var notify models.Notification if err := database.C.Where(&models.Notification{ BaseModel: models.BaseModel{ID: uint(id)}, @@ -55,13 +66,16 @@ func markNotificationRead(c *fiber.Ctx) error { } func markNotificationReadBatch(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var data struct { MessageIDs []uint `json:"messages"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } @@ -75,7 +89,10 @@ func markNotificationReadBatch(c *fiber.Ctx) error { } func addNotifySubscriber(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var data struct { Provider string `json:"provider" validate:"required"` @@ -83,7 +100,7 @@ func addNotifySubscriber(c *fiber.Ctx) error { DeviceID string `json:"device_id" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } diff --git a/pkg/internal/server/notify_api.go b/pkg/internal/server/api/notify_api.go similarity index 93% rename from pkg/internal/server/notify_api.go rename to pkg/internal/server/api/notify_api.go index 24e18de..680b9d0 100644 --- a/pkg/internal/server/notify_api.go +++ b/pkg/internal/server/api/notify_api.go @@ -1,9 +1,9 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) @@ -21,7 +21,7 @@ func notifyUser(c *fiber.Ctx) error { UserID uint `json:"user_id" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } diff --git a/pkg/internal/server/page_api.go b/pkg/internal/server/api/page_api.go similarity index 81% rename from pkg/internal/server/page_api.go rename to pkg/internal/server/api/page_api.go index b2b3958..77c7c43 100644 --- a/pkg/internal/server/page_api.go +++ b/pkg/internal/server/api/page_api.go @@ -1,9 +1,9 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "github.com/gofiber/fiber/v2" ) @@ -28,7 +28,10 @@ func getPersonalPage(c *fiber.Ctx) error { } func getOwnPersonalPage(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var page models.AccountPage if err := database.C. @@ -41,14 +44,17 @@ func getOwnPersonalPage(c *fiber.Ctx) error { } func editPersonalPage(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) var data struct { Content string `json:"content"` Links []models.AccountPageLinks `json:"links"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } diff --git a/pkg/internal/server/realm_members_api.go b/pkg/internal/server/api/realm_members_api.go similarity index 82% rename from pkg/internal/server/realm_members_api.go rename to pkg/internal/server/api/realm_members_api.go index 2bed1f1..7c16361 100644 --- a/pkg/internal/server/realm_members_api.go +++ b/pkg/internal/server/api/realm_members_api.go @@ -1,10 +1,10 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) @@ -22,7 +22,10 @@ func listRealmMembers(c *fiber.Ctx) error { func getMyRealmMember(c *fiber.Ctx) error { alias := c.Params("realm") - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) if realm, err := services.GetRealmWithAlias(alias); err != nil { return fiber.NewError(fiber.StatusNotFound, err.Error()) @@ -34,14 +37,17 @@ func getMyRealmMember(c *fiber.Ctx) error { } func addRealmMember(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) alias := c.Params("realm") var data struct { Target string `json:"target" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -65,14 +71,17 @@ func addRealmMember(c *fiber.Ctx) error { } func removeRealmMember(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) alias := c.Params("realm") var data struct { Target string `json:"target" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -96,7 +105,10 @@ func removeRealmMember(c *fiber.Ctx) error { } func leaveRealm(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) alias := c.Params("realm") realm, err := services.GetRealmWithAlias(alias) diff --git a/pkg/internal/server/realms_api.go b/pkg/internal/server/api/realms_api.go similarity index 80% rename from pkg/internal/server/realms_api.go rename to pkg/internal/server/api/realms_api.go index b4e5d8d..1a34a90 100644 --- a/pkg/internal/server/realms_api.go +++ b/pkg/internal/server/api/realms_api.go @@ -1,10 +1,10 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) @@ -27,7 +27,10 @@ func listCommunityRealm(c *fiber.Ctx) error { } func listOwnedRealm(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) if realms, err := services.ListOwnedRealm(user); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { @@ -36,7 +39,10 @@ func listOwnedRealm(c *fiber.Ctx) error { } func listAvailableRealm(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) if realms, err := services.ListAvailableRealm(user); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else { @@ -45,10 +51,10 @@ func listAvailableRealm(c *fiber.Ctx) error { } func createRealm(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) - if err := utils.CheckPermissions(c, "CreateRealms", true); err != nil { + if err := exts.EnsureGrantedPerm(c, "CreateRealms", true); err != nil { return err } + user := c.Locals("user").(models.Account) var data struct { Alias string `json:"alias" validate:"required,lowercase,min=4,max=32"` @@ -58,7 +64,7 @@ func createRealm(c *fiber.Ctx) error { IsCommunity bool `json:"is_community"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -78,7 +84,10 @@ func createRealm(c *fiber.Ctx) error { } func editRealm(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) id, _ := c.ParamsInt("realmId", 0) var data struct { @@ -89,7 +98,7 @@ func editRealm(c *fiber.Ctx) error { IsCommunity bool `json:"is_community"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return err } @@ -116,7 +125,10 @@ func editRealm(c *fiber.Ctx) error { } func deleteRealm(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) id, _ := c.ParamsInt("realmId", 0) var realm models.Realm diff --git a/pkg/internal/server/security_api.go b/pkg/internal/server/api/security_api.go similarity index 81% rename from pkg/internal/server/security_api.go rename to pkg/internal/server/api/security_api.go index 6b6a043..fba9867 100644 --- a/pkg/internal/server/security_api.go +++ b/pkg/internal/server/api/security_api.go @@ -1,13 +1,17 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "github.com/gofiber/fiber/v2" ) func getTickets(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) take := c.QueryInt("take", 0) offset := c.QueryInt("offset", 0) diff --git a/pkg/internal/server/userinfo_api.go b/pkg/internal/server/api/userinfo_api.go similarity index 97% rename from pkg/internal/server/userinfo_api.go rename to pkg/internal/server/api/userinfo_api.go index eb06de5..b200d8e 100644 --- a/pkg/internal/server/userinfo_api.go +++ b/pkg/internal/server/api/userinfo_api.go @@ -1,4 +1,4 @@ -package server +package api import ( "git.solsynth.dev/hydrogen/passport/pkg/internal/database" diff --git a/pkg/internal/server/well_known_api.go b/pkg/internal/server/api/well_known_api.go similarity index 98% rename from pkg/internal/server/well_known_api.go rename to pkg/internal/server/api/well_known_api.go index 8580210..4384450 100644 --- a/pkg/internal/server/well_known_api.go +++ b/pkg/internal/server/api/well_known_api.go @@ -1,4 +1,4 @@ -package server +package api import ( "fmt" diff --git a/pkg/internal/server/ws.go b/pkg/internal/server/api/ws.go similarity index 97% rename from pkg/internal/server/ws.go rename to pkg/internal/server/api/ws.go index 61d2d6c..4ecf40f 100644 --- a/pkg/internal/server/ws.go +++ b/pkg/internal/server/api/ws.go @@ -1,8 +1,7 @@ -package server +package api import ( "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/models" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" "github.com/gofiber/contrib/websocket" @@ -12,7 +11,7 @@ import ( ) func listenWebsocket(c *websocket.Conn) { - user := c.Locals("principal").(models.Account) + user := c.Locals("user").(models.Account) // Push connection services.ClientRegister(user, c) diff --git a/pkg/internal/server/auth_middleware.go b/pkg/internal/server/auth_middleware.go deleted file mode 100644 index 91583aa..0000000 --- a/pkg/internal/server/auth_middleware.go +++ /dev/null @@ -1,55 +0,0 @@ -package server - -import ( - "strings" - - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "github.com/gofiber/fiber/v2" -) - -func authMiddleware(c *fiber.Ctx) error { - var token string - if cookie := c.Cookies(services.CookieAccessKey); len(cookie) > 0 { - token = cookie - } - if header := c.Get(fiber.HeaderAuthorization); len(header) > 0 { - tk := strings.Replace(header, "Bearer", "", 1) - token = strings.TrimSpace(tk) - } - if query := c.Query("tk"); len(query) > 0 { - token = strings.TrimSpace(query) - } - - c.Locals("token", token) - - if err := authFunc(c); err != nil { - return err - } - - return c.Next() -} - -func authFunc(c *fiber.Ctx, overrides ...string) error { - var token string - if len(overrides) > 0 { - token = overrides[0] - } else { - if tk, ok := c.Locals("token").(string); !ok { - return fiber.NewError(fiber.StatusUnauthorized) - } else { - token = tk - } - } - - rtk := c.Cookies(services.CookieRefreshKey) - if ctx, perms, atk, rtk, err := services.Authenticate(token, rtk, 0); err == nil { - if atk != token { - services.SetJwtCookieSet(c, atk, rtk) - } - c.Locals("permissions", perms) - c.Locals("principal", ctx.Account) - return nil - } else { - return err - } -} diff --git a/pkg/internal/server/exts/auth.go b/pkg/internal/server/exts/auth.go new file mode 100644 index 0000000..5ebc09c --- /dev/null +++ b/pkg/internal/server/exts/auth.go @@ -0,0 +1,53 @@ +package exts + +import ( + "fmt" + "git.solsynth.dev/hydrogen/passport/pkg/hyper" + "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/services" + "github.com/gofiber/fiber/v2" + "strings" +) + +func AuthMiddleware(c *fiber.Ctx) error { + var atk string + if cookie := c.Cookies(hyper.CookieAtk); len(cookie) > 0 { + atk = cookie + } + if header := c.Get(fiber.HeaderAuthorization); len(header) > 0 { + tk := strings.Replace(header, "Bearer", "", 1) + atk = strings.TrimSpace(tk) + } + + c.Locals("p_token", atk) + + rtk := c.Cookies(hyper.CookieRtk) + if ctx, perms, newAtk, newRtk, err := services.Authenticate(atk, rtk, 0); err == nil { + if newAtk != atk { + SetAuthCookies(c, newAtk, newRtk) + } + c.Locals("permissions", perms) + c.Locals("user", ctx.Account) + } + + return c.Next() +} + +func EnsureAuthenticated(c *fiber.Ctx) error { + if _, ok := c.Locals("user").(models.Account); !ok { + return fiber.NewError(fiber.StatusUnauthorized) + } + + return nil +} + +func EnsureGrantedPerm(c *fiber.Ctx, key string, val any) error { + if err := EnsureAuthenticated(c); err != nil { + return err + } + perms := c.Locals("permissions").(map[string]any) + if !services.HasPermNode(perms, key, val) { + return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("missing permission: %s", key)) + } + return nil +} diff --git a/pkg/internal/server/exts/cookies.go b/pkg/internal/server/exts/cookies.go new file mode 100644 index 0000000..32afd7c --- /dev/null +++ b/pkg/internal/server/exts/cookies.go @@ -0,0 +1,27 @@ +package exts + +import ( + "git.solsynth.dev/hydrogen/passport/pkg/hyper" + "github.com/gofiber/fiber/v2" + "github.com/spf13/viper" + "time" +) + +func SetAuthCookies(c *fiber.Ctx, atk, rtk string) { + c.Cookie(&fiber.Cookie{ + Name: hyper.CookieAtk, + Value: atk, + Domain: viper.GetString("security.cookie_domain"), + SameSite: viper.GetString("security.cookie_samesite"), + Expires: time.Now().Add(60 * time.Minute), + Path: "/", + }) + c.Cookie(&fiber.Cookie{ + Name: hyper.CookieRtk, + Value: rtk, + Domain: viper.GetString("security.cookie_domain"), + SameSite: viper.GetString("security.cookie_samesite"), + Expires: time.Now().Add(24 * 30 * time.Hour), + Path: "/", + }) +} diff --git a/pkg/internal/utils/request.go b/pkg/internal/server/exts/request.go similarity index 65% rename from pkg/internal/utils/request.go rename to pkg/internal/server/exts/request.go index fd43caa..1e5a115 100644 --- a/pkg/internal/utils/request.go +++ b/pkg/internal/server/exts/request.go @@ -1,8 +1,6 @@ -package utils +package exts import ( - "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "github.com/samber/lo" @@ -21,17 +19,6 @@ func BindAndValidate(c *fiber.Ctx, out any) error { return nil } -func GetPermissions(c *fiber.Ctx) map[string]any { - return c.Locals("permissions").(map[string]any) -} - -func CheckPermissions(c *fiber.Ctx, key string, val any) error { - if !services.HasPermNode(GetPermissions(c), key, val) { - return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("requires permission: %s = %v", key, val)) - } - return nil -} - func GetRedirectUri(c *fiber.Ctx, fallback ...string) *string { if len(c.Query("redirect_uri")) > 0 { return lo.ToPtr(c.Query("redirect_uri")) diff --git a/pkg/internal/server/server.go b/pkg/internal/server/server.go index 17263e8..1f14ef0 100644 --- a/pkg/internal/server/server.go +++ b/pkg/internal/server/server.go @@ -1,11 +1,11 @@ package server import ( + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/api" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "net/http" "strings" - "github.com/gofiber/contrib/websocket" - "git.solsynth.dev/hydrogen/passport/pkg/internal" "git.solsynth.dev/hydrogen/passport/pkg/internal/i18n" "git.solsynth.dev/hydrogen/passport/pkg/internal/server/admin" @@ -61,92 +61,18 @@ func NewServer() { Output: log.Logger, })) + A.Use(exts.AuthMiddleware) A.Use(i18n.I18nMiddleware) - A.Get("/.well-known", getMetadata) - A.Get("/.well-known/openid-configuration", getOidcConfiguration) - - api := A.Group("/api").Name("API") - { - notify := api.Group("/notifications").Name("Notifications API") - { - notify.Get("/", authMiddleware, getNotifications) - notify.Post("/subscribe", authMiddleware, addNotifySubscriber) - notify.Put("/batch/read", authMiddleware, markNotificationReadBatch) - notify.Put("/:notificationId/read", authMiddleware, markNotificationRead) - } - - me := api.Group("/users/me").Name("Myself Operations") - { - - me.Put("/avatar", authMiddleware, setAvatar) - me.Put("/banner", authMiddleware, setBanner) - - me.Get("/", authMiddleware, getUserinfo) - me.Get("/page", authMiddleware, getOwnPersonalPage) - me.Put("/", authMiddleware, editUserinfo) - me.Put("/page", authMiddleware, editPersonalPage) - me.Get("/events", authMiddleware, getEvents) - me.Get("/tickets", authMiddleware, getTickets) - me.Delete("/tickets/:ticketId", authMiddleware, killSession) - - me.Post("/confirm", doRegisterConfirm) - - friends := me.Group("/friends").Name("Friends") - { - friends.Get("/", authMiddleware, listFriendship) - friends.Get("/:relatedId", authMiddleware, getFriendship) - friends.Post("/", authMiddleware, makeFriendship) - friends.Post("/:relatedId", authMiddleware, makeFriendship) - friends.Put("/:relatedId", authMiddleware, editFriendship) - friends.Delete("/:relatedId", authMiddleware, deleteFriendship) - } - } - - directory := api.Group("/users/:alias").Name("User Directory") - { - directory.Get("/", getOtherUserinfo) - directory.Get("/page", getPersonalPage) - } - - api.Post("/users", doRegister) - - api.Post("/auth", doAuthenticate) - api.Post("/auth/token", getToken) - api.Post("/auth/factors/:factorId", requestFactorToken) - - realms := api.Group("/realms").Name("Realms API") - { - realms.Get("/", listCommunityRealm) - realms.Get("/me", authMiddleware, listOwnedRealm) - realms.Get("/me/available", authMiddleware, listAvailableRealm) - realms.Get("/:realm", getRealm) - realms.Get("/:realm/members", listRealmMembers) - realms.Get("/:realm/members/me", authMiddleware, getMyRealmMember) - realms.Post("/", authMiddleware, createRealm) - realms.Put("/:realmId", authMiddleware, editRealm) - realms.Delete("/:realmId", authMiddleware, deleteRealm) - realms.Post("/:realm/members", authMiddleware, addRealmMember) - realms.Delete("/:realm/members", authMiddleware, removeRealmMember) - realms.Delete("/:realm/members/me", authMiddleware, leaveRealm) - } - - developers := api.Group("/dev").Name("Developers API") - { - developers.Post("/notify", notifyUser) - } - - api.Get("/ws", authMiddleware, websocket.New(listenWebsocket)) - } - A.Use(favicon.New(favicon.Config{ FileSystem: http.FS(pkg.FS), File: "views/favicon.png", URL: "/favicon.png", })) - admin.MapAdminEndpoints(A, authMiddleware) - ui.MapUserInterface(A, authFunc) + api.MapAPIs(A) + admin.MapAdminEndpoints(A) + ui.MapUserInterface(A) } func Listen() { diff --git a/pkg/internal/server/ui/accounts.go b/pkg/internal/server/ui/accounts.go index d8ecaa2..e4ec045 100644 --- a/pkg/internal/server/ui/accounts.go +++ b/pkg/internal/server/ui/accounts.go @@ -2,6 +2,7 @@ package ui import ( "fmt" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "html/template" "time" @@ -15,7 +16,10 @@ import ( ) func selfUserinfoPage(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return DoAuthRedirect(c) + } + user := c.Locals("user").(models.Account) var data models.Account if err := database.C. diff --git a/pkg/internal/server/ui/index.go b/pkg/internal/server/ui/index.go index 11bc703..bd150b1 100644 --- a/pkg/internal/server/ui/index.go +++ b/pkg/internal/server/ui/index.go @@ -3,28 +3,15 @@ package ui import ( "fmt" - "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" ) -func MapUserInterface(A *fiber.App, authFunc utils.AuthFunc) { - authCheckWare := func(c *fiber.Ctx) error { - var token string - if cookie := c.Cookies(services.CookieAccessKey); len(cookie) > 0 { - token = cookie - } - - c.Locals("token", token) - - if err := authFunc(c); err != nil { - uri := c.Request().URI().FullURI() - return c.Redirect(fmt.Sprintf("/sign-in?redirect_uri=%s", string(uri))) - } else { - return c.Next() - } - } +func DoAuthRedirect(c *fiber.Ctx) error { + uri := c.Request().URI().FullURI() + return c.Redirect(fmt.Sprintf("/sign-in?redirect_uri=%s", string(uri))) +} +func MapUserInterface(A *fiber.App) { pages := A.Group("/").Name("Pages") pages.Get("/", func(c *fiber.Ctx) error { @@ -35,13 +22,13 @@ func MapUserInterface(A *fiber.App, authFunc utils.AuthFunc) { pages.Get("/sign-in", signinPage) pages.Get("/mfa", mfaRequestPage) pages.Get("/mfa/apply", mfaApplyPage) - pages.Get("/authorize", authCheckWare, authorizePage) + pages.Get("/authorize", authorizePage) pages.Post("/sign-up", signupAction) pages.Post("/sign-in", signinAction) pages.Post("/mfa", mfaRequestAction) pages.Post("/mfa/apply", mfaApplyAction) - pages.Post("/authorize", authCheckWare, authorizeAction) + pages.Post("/authorize", authorizeAction) - pages.Get("/users/me", authCheckWare, selfUserinfoPage) + pages.Get("/users/me", selfUserinfoPage) } diff --git a/pkg/internal/server/ui/mfa.go b/pkg/internal/server/ui/mfa.go index 670f0f6..4fd8e24 100644 --- a/pkg/internal/server/ui/mfa.go +++ b/pkg/internal/server/ui/mfa.go @@ -3,8 +3,8 @@ package ui import ( "fmt" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/samber/lo" @@ -68,7 +68,7 @@ func mfaRequestAction(c *fiber.Ctx) error { } redirectBackUri := "/sign-in" - err := utils.BindAndValidate(c, &data) + err := exts.BindAndValidate(c, &data) if data.TicketID > 0 { redirectBackUri = fmt.Sprintf("/mfa?ticket=%d", data.TicketID) @@ -95,7 +95,7 @@ func mfaRequestAction(c *fiber.Ctx) error { } return flash.WithData(c, fiber.Map{ - "redirect_uri": utils.GetRedirectUri(c), + "redirect_uri": exts.GetRedirectUri(c), }).Redirect(fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, factor.ID)) } @@ -145,7 +145,7 @@ func mfaApplyAction(c *fiber.Ctx) error { } redirectBackUri := "/sign-in" - err := utils.BindAndValidate(c, &data) + err := exts.BindAndValidate(c, &data) if data.TicketID > 0 { redirectBackUri = fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, data.FactorID) @@ -187,8 +187,8 @@ func mfaApplyAction(c *fiber.Ctx) error { "message": fmt.Sprintf("failed to exchange token: %v", err.Error()), }).Redirect("/sign-in") } else { - services.SetJwtCookieSet(c, access, refresh) + exts.SetAuthCookies(c, access, refresh) } - return c.Redirect(lo.FromPtr(utils.GetRedirectUri(c, "/users/me"))) + return c.Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/users/me"))) } diff --git a/pkg/internal/server/ui/oauth.go b/pkg/internal/server/ui/oauth.go index 839eabf..946a17c 100644 --- a/pkg/internal/server/ui/oauth.go +++ b/pkg/internal/server/ui/oauth.go @@ -4,6 +4,7 @@ import ( "fmt" "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" "github.com/gofiber/fiber/v2" "github.com/nicksnyder/go-i18n/v2/i18n" @@ -16,7 +17,11 @@ import ( func authorizePage(c *fiber.Ctx) error { localizer := c.Locals("localizer").(*i18n.Localizer) - user := c.Locals("principal").(models.Account) + + if err := exts.EnsureAuthenticated(c); err != nil { + return DoAuthRedirect(c) + } + user := c.Locals("user").(models.Account) id := c.Query("client_id") redirect := c.Query("redirect_uri") @@ -81,12 +86,19 @@ func authorizePage(c *fiber.Ctx) error { } func authorizeAction(c *fiber.Ctx) error { - user := c.Locals("principal").(models.Account) + if err := exts.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(models.Account) id := c.Query("client_id") response := c.Query("response_type") redirect := c.Query("redirect_uri") scope := c.Query("scope") + if err := exts.EnsureAuthenticated(c); err != nil { + return DoAuthRedirect(c) + } + redirectBackUri := "/authorize?" + string(c.Request().URI().QueryString()) if len(scope) <= 0 { diff --git a/pkg/internal/server/ui/signin.go b/pkg/internal/server/ui/signin.go index 443101b..df87970 100644 --- a/pkg/internal/server/ui/signin.go +++ b/pkg/internal/server/ui/signin.go @@ -2,8 +2,8 @@ package ui import ( "fmt" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/samber/lo" @@ -47,7 +47,7 @@ func signinAction(c *fiber.Ctx) error { Password string `form:"password" validate:"required"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return flash.WithInfo(c, fiber.Map{ "message": err.Error(), }).Redirect("/sign-in") @@ -76,7 +76,7 @@ func signinAction(c *fiber.Ctx) error { if ticket.IsAvailable() != nil { return flash.WithData(c, fiber.Map{ - "redirect_uri": utils.GetRedirectUri(c), + "redirect_uri": exts.GetRedirectUri(c), }).Redirect(fmt.Sprintf("/mfa?ticket=%d", ticket.ID)) } @@ -86,8 +86,8 @@ func signinAction(c *fiber.Ctx) error { "message": fmt.Sprintf("failed to exchange token: %v", err.Error()), }).Redirect("/sign-in") } else { - services.SetJwtCookieSet(c, access, refresh) + exts.SetAuthCookies(c, access, refresh) } - return c.Redirect(lo.FromPtr(utils.GetRedirectUri(c, "/users/me"))) + return c.Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/users/me"))) } diff --git a/pkg/internal/server/ui/signup.go b/pkg/internal/server/ui/signup.go index cf5bfa9..28867a2 100644 --- a/pkg/internal/server/ui/signup.go +++ b/pkg/internal/server/ui/signup.go @@ -4,8 +4,8 @@ import ( "fmt" "git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/models" + "git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts" "git.solsynth.dev/hydrogen/passport/pkg/internal/services" - "git.solsynth.dev/hydrogen/passport/pkg/internal/utils" "github.com/gofiber/fiber/v2" "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/samber/lo" @@ -52,7 +52,7 @@ func signupAction(c *fiber.Ctx) error { MagicToken string `form:"magic_token"` } - if err := utils.BindAndValidate(c, &data); err != nil { + if err := exts.BindAndValidate(c, &data); err != nil { return flash.WithInfo(c, fiber.Map{ "message": err.Error(), }).Redirect("/sign-up") @@ -82,6 +82,6 @@ func signupAction(c *fiber.Ctx) error { } else { return flash.WithInfo(c, fiber.Map{ "message": "account has been created. now you can sign in!", - }).Redirect(lo.FromPtr(utils.GetRedirectUri(c, "/sign-in"))) + }).Redirect(lo.FromPtr(exts.GetRedirectUri(c, "/sign-in"))) } } diff --git a/pkg/internal/services/auth.go b/pkg/internal/services/auth.go index 9e40307..ffbaaeb 100644 --- a/pkg/internal/services/auth.go +++ b/pkg/internal/services/auth.go @@ -17,23 +17,23 @@ var ( authContextCache = make(map[string]models.AuthContext) ) -func Authenticate(access, refresh string, depth int) (ctx models.AuthContext, perms map[string]any, newAccess, newRefresh string, err error) { +func Authenticate(atk, rtk string, rty int) (ctx models.AuthContext, perms map[string]any, newAtk, newRtk string, err error) { var claims PayloadClaims - claims, err = DecodeJwt(access) + claims, err = DecodeJwt(atk) if err != nil { - if len(refresh) > 0 && depth < 1 { + if len(rtk) > 0 && rty < 1 { // Auto refresh and retry - newAccess, newRefresh, err = RefreshToken(refresh) + newAtk, newRtk, err = RefreshToken(rtk) if err == nil { - return Authenticate(newAccess, newRefresh, depth+1) + return Authenticate(newAtk, newRtk, rty+1) } } err = fiber.NewError(fiber.StatusUnauthorized, fmt.Sprintf("invalid auth key: %v", err)) return } - newAccess = access - newRefresh = refresh + newAtk = atk + newRtk = rtk if ctx, err = GetAuthContext(claims.ID); err == nil { var heldPerms map[string]any diff --git a/pkg/internal/services/jwt.go b/pkg/internal/services/jwt.go index de83bd5..a198b2f 100644 --- a/pkg/internal/services/jwt.go +++ b/pkg/internal/services/jwt.go @@ -2,16 +2,12 @@ package services import ( "fmt" - "github.com/gofiber/fiber/v2" "time" "github.com/golang-jwt/jwt/v5" "github.com/spf13/viper" ) -var CookieAccessKey = "passport_auth_key" -var CookieRefreshKey = "passport_refresh_key" - type PayloadClaims struct { jwt.RegisteredClaims @@ -60,22 +56,3 @@ func DecodeJwt(str string) (PayloadClaims, error) { return claims, fmt.Errorf("unexpected token payload: not payload claims type") } } - -func SetJwtCookieSet(c *fiber.Ctx, access, refresh string) { - c.Cookie(&fiber.Cookie{ - Name: CookieAccessKey, - Value: access, - Domain: viper.GetString("security.cookie_domain"), - SameSite: viper.GetString("security.cookie_samesite"), - Expires: time.Now().Add(60 * time.Minute), - Path: "/", - }) - c.Cookie(&fiber.Cookie{ - Name: CookieRefreshKey, - Value: refresh, - Domain: viper.GetString("security.cookie_domain"), - SameSite: viper.GetString("security.cookie_samesite"), - Expires: time.Now().Add(24 * 30 * time.Hour), - Path: "/", - }) -} diff --git a/pkg/internal/utils/auth.go b/pkg/internal/utils/auth.go deleted file mode 100644 index b87ed7a..0000000 --- a/pkg/internal/utils/auth.go +++ /dev/null @@ -1,5 +0,0 @@ -package utils - -import "github.com/gofiber/fiber/v2" - -type AuthFunc func(c *fiber.Ctx, overrides ...string) error