feat(be/fe): enable captcha (#69)
* feat(ui): enable captcha * feat(server): enable captcha * fix(ui): fix login pane layout * fix(config): remove unused config and files * fix(be/fe): clean up code * chore(fe/be): clean up code
This commit is contained in:
parent
021e5090be
commit
1fcb2223a0
22 changed files with 262 additions and 82 deletions
42
src/handlers/multiusers/captcha.go
Normal file
42
src/handlers/multiusers/captcha.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package multiusers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/dchest/captcha"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
q "github.com/ihexxa/quickshare/src/handlers"
|
||||
)
|
||||
|
||||
type GetCaptchaIDResp struct {
|
||||
CaptchaID string `json:"id"`
|
||||
}
|
||||
|
||||
func (h *MultiUsersSvc) GetCaptchaID(c *gin.Context) {
|
||||
captchaID := captcha.New()
|
||||
c.JSON(200, &GetCaptchaIDResp{CaptchaID: captchaID})
|
||||
}
|
||||
|
||||
// path: /captchas/imgs?id=xxx
|
||||
func (h *MultiUsersSvc) GetCaptchaImg(c *gin.Context) {
|
||||
captchaID := c.Query(q.CaptchaIDParam)
|
||||
if captchaID == "" {
|
||||
c.JSON(q.ErrResp(c, 400, errors.New("empty captcha ID")))
|
||||
return
|
||||
}
|
||||
|
||||
capWidth := h.cfg.IntOr("Users.CaptchaWidth", 256)
|
||||
capHeight := h.cfg.IntOr("Users.CaptchaHeight", 64)
|
||||
|
||||
// TODO: improve performance
|
||||
buf := new(bytes.Buffer)
|
||||
err := captcha.WriteImage(buf, captchaID, capWidth, capHeight)
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 500, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.Data(200, "image/png", buf.Bytes())
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/dchest/captcha"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ihexxa/gocfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
@ -61,6 +62,8 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
|
|||
apiRuleCname(userstore.AdminRole, "DELETE", "/v1/fs/uploadings"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/v1/fs/metadata"): true,
|
||||
apiRuleCname(userstore.AdminRole, "OPTIONS", "/v1/settings/health"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/v1/captchas/"): true,
|
||||
apiRuleCname(userstore.AdminRole, "GET", "/v1/captchas/imgs"): true,
|
||||
// user rules
|
||||
apiRuleCname(userstore.UserRole, "GET", "/"): true,
|
||||
apiRuleCname(userstore.UserRole, "GET", publicPath): true,
|
||||
|
@ -82,6 +85,8 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
|
|||
apiRuleCname(userstore.UserRole, "DELETE", "/v1/fs/uploadings"): true,
|
||||
apiRuleCname(userstore.UserRole, "GET", "/v1/fs/metadata"): true,
|
||||
apiRuleCname(userstore.UserRole, "OPTIONS", "/v1/settings/health"): true,
|
||||
apiRuleCname(userstore.UserRole, "GET", "/v1/captchas/"): true,
|
||||
apiRuleCname(userstore.UserRole, "GET", "/v1/captchas/imgs"): true,
|
||||
// visitor rules
|
||||
apiRuleCname(userstore.VisitorRole, "GET", "/"): true,
|
||||
apiRuleCname(userstore.VisitorRole, "GET", publicPath): true,
|
||||
|
@ -90,6 +95,8 @@ func NewMultiUsersSvc(cfg gocfg.ICfg, deps *depidx.Deps) (*MultiUsersSvc, error)
|
|||
apiRuleCname(userstore.VisitorRole, "GET", "/v1/users/self"): true,
|
||||
apiRuleCname(userstore.VisitorRole, "GET", "/v1/fs/files"): true,
|
||||
apiRuleCname(userstore.VisitorRole, "OPTIONS", "/v1/settings/health"): true,
|
||||
apiRuleCname(userstore.VisitorRole, "GET", "/v1/captchas/"): true,
|
||||
apiRuleCname(userstore.VisitorRole, "GET", "/v1/captchas/imgs"): true,
|
||||
}
|
||||
|
||||
return &MultiUsersSvc{
|
||||
|
@ -122,8 +129,10 @@ func (h *MultiUsersSvc) IsInited() bool {
|
|||
}
|
||||
|
||||
type LoginReq struct {
|
||||
User string `json:"user"`
|
||||
Pwd string `json:"pwd"`
|
||||
User string `json:"user"`
|
||||
Pwd string `json:"pwd"`
|
||||
CaptchaID string `json:"captchaId"`
|
||||
CaptchaInput string `json:"captchaInput"`
|
||||
}
|
||||
|
||||
func (h *MultiUsersSvc) Login(c *gin.Context) {
|
||||
|
@ -133,6 +142,15 @@ func (h *MultiUsersSvc) Login(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: add rate limiter for verifying
|
||||
captchaEnabled := h.cfg.BoolOr("Users.CaptchaEnabled", true)
|
||||
if captchaEnabled {
|
||||
if !captcha.VerifyString(req.CaptchaID, req.CaptchaInput) {
|
||||
c.JSON(q.ErrResp(c, 403, errors.New("login failed")))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
user, err := h.deps.Users().GetUserByName(req.User)
|
||||
if err != nil {
|
||||
c.JSON(q.ErrResp(c, 500, err))
|
||||
|
|
|
@ -15,14 +15,15 @@ var (
|
|||
FsDir = "files"
|
||||
FsRootDir = "files"
|
||||
|
||||
UserIDParam = "uid"
|
||||
UserParam = "user"
|
||||
PwdParam = "pwd"
|
||||
NewPwdParam = "newpwd"
|
||||
RoleParam = "role"
|
||||
ExpireParam = "expire"
|
||||
TokenCookie = "tk"
|
||||
LastID = "lid"
|
||||
UserIDParam = "uid"
|
||||
UserParam = "user"
|
||||
PwdParam = "pwd"
|
||||
NewPwdParam = "newpwd"
|
||||
RoleParam = "role"
|
||||
ExpireParam = "expire"
|
||||
CaptchaIDParam = "capid"
|
||||
TokenCookie = "tk"
|
||||
LastID = "lid"
|
||||
|
||||
ErrAccessDenied = errors.New("access denied")
|
||||
ErrUnauthorized = errors.New("unauthorized")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue