mirror of
https://github.com/makayabou/asg-server.git
synced 2026-05-02 17:43:36 +02:00
[api] introduce userauth middleware and helpers
This commit is contained in:
parent
d9d3657701
commit
d19787888c
@ -5,11 +5,11 @@ import (
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/devices"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/logs"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/messages"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/webhooks"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/basicauth"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@ -46,24 +46,10 @@ func (h *thirdPartyHandler) Register(router fiber.Router) {
|
||||
|
||||
h.healthHandler.Register(router)
|
||||
|
||||
router.Use(basicauth.New(basicauth.Config{
|
||||
Authorizer: func(username string, password string) bool {
|
||||
return len(username) > 0 && len(password) > 0
|
||||
},
|
||||
}), func(c *fiber.Ctx) error {
|
||||
username := c.Locals("username").(string)
|
||||
password := c.Locals("password").(string)
|
||||
|
||||
user, err := h.authSvc.AuthorizeUser(username, password)
|
||||
if err != nil {
|
||||
h.Logger.Error("failed to authorize user", zap.Error(err))
|
||||
return fiber.ErrUnauthorized
|
||||
}
|
||||
|
||||
c.Locals("user", user)
|
||||
|
||||
return c.Next()
|
||||
})
|
||||
router.Use(
|
||||
userauth.New(h.authSvc),
|
||||
userauth.UserRequired(),
|
||||
)
|
||||
|
||||
h.messagesHandler.Register(router.Group("/message")) // TODO: remove after 2025-12-31
|
||||
h.messagesHandler.Register(router.Group("/messages"))
|
||||
|
||||
@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/android-sms-gateway/client-go/smsgateway"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
|
||||
"github.com/android-sms-gateway/server/pkg/types"
|
||||
"github.com/capcom6/go-helpers/slices"
|
||||
@ -62,7 +62,7 @@ func (h *ThirdPartyController) getDevices(user models.User, c *fiber.Ctx) error
|
||||
}
|
||||
|
||||
func (h *ThirdPartyController) Register(router fiber.Router) {
|
||||
router.Get("", auth.WithUser(h.getDevices))
|
||||
router.Get("", userauth.WithUser(h.getDevices))
|
||||
}
|
||||
|
||||
func NewThirdPartyController(params thirdPartyControllerParams) *ThirdPartyController {
|
||||
|
||||
@ -2,8 +2,8 @@ package logs
|
||||
|
||||
import (
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/fx"
|
||||
@ -40,7 +40,7 @@ func (h *ThirdPartyController) get(user models.User, c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
func (h *ThirdPartyController) Register(router fiber.Router) {
|
||||
router.Get("", auth.WithUser(h.get))
|
||||
router.Get("", userauth.WithUser(h.get))
|
||||
}
|
||||
|
||||
func NewThirdPartyController(params thirdPartyControllerParams) *ThirdPartyController {
|
||||
|
||||
@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/android-sms-gateway/client-go/smsgateway"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/devices"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/messages"
|
||||
"github.com/go-playground/validator/v10"
|
||||
@ -163,10 +163,10 @@ func (h *ThirdPartyController) postInboxExport(user models.User, c *fiber.Ctx) e
|
||||
}
|
||||
|
||||
func (h *ThirdPartyController) Register(router fiber.Router) {
|
||||
router.Post("", auth.WithUser(h.post))
|
||||
router.Get(":id", auth.WithUser(h.get))
|
||||
router.Post("", userauth.WithUser(h.post))
|
||||
router.Get(":id", userauth.WithUser(h.get))
|
||||
|
||||
router.Post("inbox/export", auth.WithUser(h.postInboxExport))
|
||||
router.Post("inbox/export", userauth.WithUser(h.postInboxExport))
|
||||
}
|
||||
|
||||
func NewThirdPartyController(params thirdPartyControllerParams) *ThirdPartyController {
|
||||
|
||||
100
internal/sms-gateway/handlers/middlewares/userauth/userauth.go
Normal file
100
internal/sms-gateway/handlers/middlewares/userauth/userauth.go
Normal file
@ -0,0 +1,100 @@
|
||||
package userauth
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
const LocalsUser = "user"
|
||||
|
||||
// New returns a middleware that will check if the request contains a valid
|
||||
// "Authorization" header in the form of "Basic <base64 encoded username:password>".
|
||||
// If the header is valid, the middleware will authorize the user and store the user
|
||||
// in the request's Locals under the key LocalsUser. If the header is invalid, the
|
||||
// middleware will call c.Next() and continue with the request.
|
||||
func New(authSvc *auth.Service) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Get authorization header
|
||||
auth := c.Get(fiber.HeaderAuthorization)
|
||||
|
||||
// Check if the header contains content besides "basic".
|
||||
if len(auth) <= 6 || !strings.EqualFold(auth[:6], "basic ") {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Decode the header contents
|
||||
raw, err := base64.StdEncoding.DecodeString(auth[6:])
|
||||
if err != nil {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Get the credentials
|
||||
creds := utils.UnsafeString(raw)
|
||||
|
||||
// Check if the credentials are in the correct form
|
||||
// which is "username:password".
|
||||
index := strings.Index(creds, ":")
|
||||
if index == -1 {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Get the username and password
|
||||
username := creds[:index]
|
||||
password := creds[index+1:]
|
||||
|
||||
user, err := authSvc.AuthorizeUser(username, password)
|
||||
if err != nil {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
c.Locals(LocalsUser, user)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// HasUser checks if a user is present in the Locals of the given context.
|
||||
// It returns true if the Locals contain a user under the key LocalsUser,
|
||||
// otherwise returns false.
|
||||
func HasUser(c *fiber.Ctx) bool {
|
||||
return c.Locals(LocalsUser) != nil
|
||||
}
|
||||
|
||||
// GetUser returns the user stored in the Locals under the key LocalsUser.
|
||||
// It is a convenience function that wraps the call to c.Locals(LocalsUser) and
|
||||
// casts the result to models.User.
|
||||
//
|
||||
// It panics if the value stored in Locals is not a models.User.
|
||||
func GetUser(c *fiber.Ctx) models.User {
|
||||
return c.Locals(LocalsUser).(models.User)
|
||||
}
|
||||
|
||||
// UserRequired is a middleware that ensures a user is present in the request's Locals.
|
||||
// If a user is not found, it returns an unauthorized error, otherwise it passes control
|
||||
// to the next handler in the stack.
|
||||
func UserRequired() fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
if !HasUser(c) {
|
||||
return fiber.ErrUnauthorized
|
||||
}
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// WithUser is a decorator that provides the current user to the handler.
|
||||
// It assumes that the user is stored in the Locals under the key LocalsUser.
|
||||
// If the user is not present, it will panic.
|
||||
//
|
||||
// It is a convenience function that wraps the call to GetUser and calls the
|
||||
// handler with the user as the first argument.
|
||||
func WithUser(handler func(models.User, *fiber.Ctx) error) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
return handler(GetUser(c), c)
|
||||
}
|
||||
}
|
||||
@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/android-sms-gateway/client-go/smsgateway"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/base"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/handlers/middlewares/userauth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/models"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/auth"
|
||||
"github.com/android-sms-gateway/server/internal/sms-gateway/modules/webhooks"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
@ -104,9 +104,9 @@ func (h *ThirdPartyController) delete(user models.User, c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
func (h *ThirdPartyController) Register(router fiber.Router) {
|
||||
router.Get("", auth.WithUser(h.get))
|
||||
router.Post("", auth.WithUser(h.post))
|
||||
router.Delete("/:id", auth.WithUser(h.delete))
|
||||
router.Get("", userauth.WithUser(h.get))
|
||||
router.Post("", userauth.WithUser(h.post))
|
||||
router.Delete("/:id", userauth.WithUser(h.delete))
|
||||
}
|
||||
|
||||
func NewThirdPartyController(params thirdPartyControllerParams) *ThirdPartyController {
|
||||
|
||||
@ -5,12 +5,6 @@ import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func WithUser(handler func(models.User, *fiber.Ctx) error) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
return handler(c.Locals("user").(models.User), c)
|
||||
}
|
||||
}
|
||||
|
||||
func WithDevice(handler func(models.Device, *fiber.Ctx) error) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
return handler(c.Locals("device").(models.Device), c)
|
||||
|
||||
@ -78,5 +78,5 @@ DELETE {{localUrl}}/webhooks/LreFUt-Z3sSq0JufY9uWB HTTP/1.1
|
||||
Authorization: Basic {{localCredentials}}
|
||||
|
||||
###
|
||||
GET {{localUrl}}/logs?from=2024-08-01T13:19:02.093%2B07:00 HTTP/1.1
|
||||
GET {{localUrl}}/logs?from=2025-02-05T20:39:46.190%2B07:00 HTTP/1.1
|
||||
Authorization: Basic {{localCredentials}}
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
GET {{baseUrl}}/health HTTP/1.1
|
||||
|
||||
###
|
||||
GET {{baseUrl}}/api/3rdparty/v1/health HTTP/1.1
|
||||
GET {{baseUrl}}/3rdparty/v1/health HTTP/1.1
|
||||
|
||||
###
|
||||
POST {{baseUrl}}/api/3rdparty/v1/messages?skipPhoneValidation=false HTTP/1.1
|
||||
POST {{baseUrl}}/3rdparty/v1/messages?skipPhoneValidation=false HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Authorization: Basic {{credentials}}
|
||||
|
||||
@ -25,7 +25,7 @@ Authorization: Basic {{credentials}}
|
||||
}
|
||||
|
||||
###
|
||||
POST {{baseUrl}}/api/3rdparty/v1/messages HTTP/1.1
|
||||
POST {{baseUrl}}/3rdparty/v1/messages HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Authorization: Basic {{credentials}}
|
||||
|
||||
@ -41,7 +41,7 @@ Authorization: Basic {{credentials}}
|
||||
}
|
||||
|
||||
###
|
||||
GET {{baseUrl}}/api/3rdparty/v1/messages/K56aIsVsQ2rECdv_ajzTd HTTP/1.1
|
||||
GET {{baseUrl}}/3rdparty/v1/messages/K56aIsVsQ2rECdv_ajzTd HTTP/1.1
|
||||
Authorization: Basic {{credentials}}
|
||||
|
||||
###
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user