fix(singleuser): fix bugs in single user handlers
This commit is contained in:
parent
31a1a331f7
commit
4d6e7ff938
10 changed files with 194 additions and 45 deletions
|
@ -2,15 +2,30 @@ package singleuserhdr
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ihexxa/gocfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/ihexxa/quickshare/src/depidx"
|
||||
q "github.com/ihexxa/quickshare/src/handlers"
|
||||
)
|
||||
|
||||
var ErrInvalidUser = errors.New("invalid user name or password")
|
||||
var (
|
||||
ErrInvalidUser = errors.New("invalid user name or password")
|
||||
ErrInvalidConfig = errors.New("invalid user config")
|
||||
UserParam = "user"
|
||||
PwdParam = "pwd"
|
||||
RoleParam = "role"
|
||||
ExpireParam = "expire"
|
||||
TokenCookie = "tk"
|
||||
AdminRole = "admin"
|
||||
VisitorRole = "visitor"
|
||||
UsersNamespace = "users"
|
||||
RolesNamespace = "roles"
|
||||
)
|
||||
|
||||
type SimpleUserHandlers struct {
|
||||
cfg gocfg.ICfg
|
||||
|
@ -24,52 +39,52 @@ func NewSimpleUserHandlers(cfg gocfg.ICfg, deps *depidx.Deps) *SimpleUserHandler
|
|||
}
|
||||
}
|
||||
|
||||
func (hdr *SimpleUserHandlers) Login(c *gin.Context) {
|
||||
userName := c.Query("username")
|
||||
pwd := c.Query("pwd")
|
||||
if userName == "" || pwd == "" {
|
||||
c.JSON(q.ErrResp(c, 400, ErrInvalidUser))
|
||||
return
|
||||
}
|
||||
|
||||
expectedName, ok1 := hdr.deps.KV().GetString("username")
|
||||
expectedPwd, ok2 := hdr.deps.KV().GetString("pwd")
|
||||
func (h *SimpleUserHandlers) Login(c *gin.Context) {
|
||||
user, ok1 := c.GetPostForm(UserParam)
|
||||
pwd, ok2 := c.GetPostForm(PwdParam)
|
||||
if !ok1 || !ok2 {
|
||||
c.JSON(q.ErrResp(c, 400, ErrInvalidUser))
|
||||
c.JSON(q.ErrResp(c, 401, ErrInvalidUser))
|
||||
return
|
||||
}
|
||||
|
||||
if userName != expectedName || pwd != expectedPwd {
|
||||
c.JSON(q.ErrResp(c, 400, ErrInvalidUser))
|
||||
expectedHash, ok := h.deps.KV().GetStringIn(UsersNamespace, user)
|
||||
if !ok {
|
||||
c.JSON(q.ErrResp(c, 500, ErrInvalidConfig))
|
||||
return
|
||||
}
|
||||
token, err := hdr.deps.Token().ToToken(map[string]string{
|
||||
"username": expectedName,
|
||||
|
||||
err := bcrypt.CompareHashAndPassword([]byte(expectedHash), []byte(pwd))
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 401, ErrInvalidUser))
|
||||
return
|
||||
}
|
||||
|
||||
role, ok := h.deps.KV().GetStringIn(RolesNamespace, user)
|
||||
if !ok {
|
||||
c.JSON(q.ErrResp(c, 500, ErrInvalidConfig))
|
||||
return
|
||||
}
|
||||
ttl := h.cfg.GrabInt("Users.CookieTTL")
|
||||
token, err := h.deps.Token().ToToken(map[string]string{
|
||||
UserParam: user,
|
||||
RoleParam: role,
|
||||
ExpireParam: fmt.Sprintf("%d", time.Now().Unix()+int64(ttl)),
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 500, err))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: use config
|
||||
c.SetCookie("token", token, 3600, "/", "localhost", false, true)
|
||||
hostname := h.cfg.GrabString("Server.Host")
|
||||
secure := h.cfg.GrabBool("Users.CookieSecure")
|
||||
httpOnly := h.cfg.GrabBool("Users.CookieHttpOnly")
|
||||
c.SetCookie(TokenCookie, token, ttl, "/", hostname, secure, httpOnly)
|
||||
|
||||
c.JSON(q.Resp(200))
|
||||
}
|
||||
|
||||
func (hdr *SimpleUserHandlers) Logout(c *gin.Context) {
|
||||
token, err := c.Cookie("token")
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 400, err))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: // check if token expired
|
||||
_, err = hdr.deps.Token().FromToken(token, map[string]string{"token": ""})
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 400, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.SetCookie("token", "", 0, "/", "localhost", false, true)
|
||||
func (h *SimpleUserHandlers) Logout(c *gin.Context) {
|
||||
// token alreay verified in the authn middleware
|
||||
c.SetCookie(TokenCookie, "", 0, "/", "nohost", false, true)
|
||||
c.JSON(q.Resp(200))
|
||||
}
|
||||
|
|
65
src/handlers/singleuserhdr/middlewares.go
Normal file
65
src/handlers/singleuserhdr/middlewares.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package singleuserhdr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
q "github.com/ihexxa/quickshare/src/handlers"
|
||||
)
|
||||
|
||||
func GetHandlerName(fullname string) (string, error) {
|
||||
parts := strings.Split(fullname, ".")
|
||||
if len(parts) == 0 {
|
||||
return "", errors.New("invalid handler name")
|
||||
}
|
||||
return parts[len(parts)-1], nil
|
||||
}
|
||||
|
||||
func (h *SimpleUserHandlers) Auth() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
handlerName, err := GetHandlerName(c.HandlerName())
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 401, err))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: may also check the path
|
||||
enableAuth := h.cfg.GrabBool("Users.EnableAuth")
|
||||
if enableAuth && handlerName != "Login-fm" {
|
||||
token, err := c.Cookie(TokenCookie)
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 401, err))
|
||||
return
|
||||
}
|
||||
|
||||
claims := map[string]string{
|
||||
UserParam: "",
|
||||
RoleParam: "",
|
||||
ExpireParam: "",
|
||||
}
|
||||
_, err = h.deps.Token().FromToken(token, claims)
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 401, err))
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
expire, err := strconv.ParseInt(claims[ExpireParam], 10, 64)
|
||||
if err != nil || expire <= now {
|
||||
c.JSON(q.ErrResp(c, 401, err))
|
||||
return
|
||||
}
|
||||
|
||||
// visitor is only allowed to download
|
||||
if claims[UserParam] != AdminRole && handlerName != "Download-fm" {
|
||||
c.JSON(q.ErrResp(c, 401, err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue