Skip to content

Commit

Permalink
fix and refactor captcha and limiter
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqcode committed Jan 24, 2024
1 parent 0d35e66 commit 570d567
Show file tree
Hide file tree
Showing 21 changed files with 135 additions and 170 deletions.
23 changes: 11 additions & 12 deletions internal/captcha/pages/geetest.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,20 @@

gt.appendTo("#captcha").onSuccess(function (e) {
var result = gt.getValidate();
var form = new FormData()
form.append("value", JSON.stringify(result))
console.log("[极验验证结果] ", result)
fetch("./check", {
fetch("./verify", {
method: 'POST',
body: form,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ value: JSON.stringify(result) }),
})
.then(function (resp) {
return resp.json()
})
.then(function (json) {
if (json.success) {
console.log("验证成功:" + json)
} else {
alert("验证失败:" + json.msg || '')
.then(function (res) {
if (!res.ok) {
res.json().then(json => {
alert("验证失败:" + res.status + " " + json.msg || '')
})
}
})
.catch(function (err) {
Expand Down
23 changes: 11 additions & 12 deletions internal/captcha/pages/hcaptcha.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,19 @@
hcaptcha.render("container", {
sitekey: "{{.site_key}}",
callback: function(token) {
var form = new FormData()
form.append("value", token)
fetch("./check", {
fetch("./verify", {
method: 'POST',
body: form,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ value: token }),
})
.then(function (resp) {
return resp.json()
})
.then(function (json) {
if (json.success) {
console.log("验证成功:" + json)
} else {
alert("验证失败:" + json.msg || '')
.then(function (res) {
if (!res.ok) {
res.json().then(json => {
alert("验证失败:" + res.status + " " + json.msg || '')
})
}
})
.catch(function (err) {
Expand Down
23 changes: 11 additions & 12 deletions internal/captcha/pages/recaptcha.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,19 @@
grecaptcha.render("container", {
sitekey: "{{.site_key}}",
callback: function(token) {
var form = new FormData()
form.append("value", token)
fetch("./check", {
fetch("./verify", {
method: 'POST',
body: form,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ value: token }),
})
.then(function (resp) {
return resp.json()
})
.then(function (json) {
if (json.success) {
console.log("验证成功:" + json)
} else {
alert("验证失败:" + json.msg || '')
.then(function (res) {
if (!res.ok) {
res.json().then(json => {
alert("验证失败:" + res.status + " " + json.msg || '')
})
}
})
.catch(function (err) {
Expand Down
23 changes: 11 additions & 12 deletions internal/captcha/pages/turnstile.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,19 @@
const turnstileOptions = {
sitekey: '{{.site_key}}',
callback: function(token) {
var form = new FormData()
form.append("value", token)
fetch("./check", {
fetch("./verify", {
method: 'POST',
body: form,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ value: token }),
})
.then(function (resp) {
return resp.json()
})
.then(function (json) {
if (json.success) {
console.log("验证成功:" + json)
} else {
alert("验证失败:" + json.msg || '')
.then(function (res) {
if (!res.ok) {
res.json().then(json => {
alert("验证失败:" + res.status + " " + json.msg || '')
})
}
})
.catch(function (err) {
Expand Down
62 changes: 58 additions & 4 deletions server/common/captcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import (

"github.com/ArtalkJS/Artalk/internal/captcha"
"github.com/ArtalkJS/Artalk/internal/core"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/server/middleware/limiter"
"github.com/gofiber/fiber/v2"
)

func GetLimiter[T any](c *fiber.Ctx) (lmt *T, error error) {
l := c.Locals("limiter").(*T)
if l == nil {
return nil, RespError(c, 500, "limiter is not initialize")
func GetLimiter(c *fiber.Ctx) (lmt *limiter.Limiter, err error) {
l, ok := c.Locals("limiter").(*limiter.Limiter)
if l == nil || !ok {
return nil, RespError(c, 500, "limiter is not initialize, but middleware is used")
}
return l, nil
}
Expand All @@ -25,3 +27,55 @@ func NewCaptchaChecker(app *core.App, c *fiber.Ctx) captcha.Checker {
},
})
}

func LimiterGuard(app *core.App, handler fiber.Handler) fiber.Handler {
return func(c *fiber.Ctx) error {
limiter, err := GetLimiter(c)
if err != nil {
return err
}

// 关闭验证码功能,直接 Skip
if !app.Conf().Captcha.Enabled {
return handler(c)
}

// 管理员直接忽略
if CheckIsAdminReq(app, c) {
return handler(c)
}

// 检测是否需要验证码
ip := c.IP()
if limiter.IsPass(ip) {
// 无需验证码
err := handler(c)

if c.Method() != fiber.MethodOptions { // 忽略 Options 请求
limiter.Log(ip) // 记录操作
}

return err
} else {
// create new captcha checker instance
cap := NewCaptchaChecker(app, c)

// response need captcha check
respData := Map{
"need_captcha": true,
}

switch cap.Type() {
case captcha.Image:
// 图片验证码
img, _ := cap.Get()
respData["img_data"] = string(img)
case captcha.IFrame:
// iFrame 验证模式
respData["iframe"] = true
}

return RespError(c, 403, i18n.T("Captcha required"), respData)
}
}
}
5 changes: 2 additions & 3 deletions server/handler/captcha_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package handler

import (
"github.com/ArtalkJS/Artalk/internal/core"
"github.com/ArtalkJS/Artalk/internal/limiter"
"github.com/ArtalkJS/Artalk/server/common"
"github.com/gofiber/fiber/v2"
)
Expand All @@ -20,8 +19,8 @@ type ResponseCaptchaStatus struct {
// @Router /captcha/status [get]
func CaptchaStatus(app *core.App, router fiber.Router) {
router.Get("/captcha/status", func(c *fiber.Ctx) error {
limiter, err := common.GetLimiter[limiter.Limiter](c)
if limiter == nil {
limiter, err := common.GetLimiter(c)
if err != nil {
return err
}

Expand Down
5 changes: 2 additions & 3 deletions server/handler/captcha_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"github.com/ArtalkJS/Artalk/internal/captcha"
"github.com/ArtalkJS/Artalk/internal/core"
"github.com/ArtalkJS/Artalk/internal/i18n"
"github.com/ArtalkJS/Artalk/internal/limiter"
"github.com/ArtalkJS/Artalk/internal/log"
"github.com/ArtalkJS/Artalk/server/common"
"github.com/gofiber/fiber/v2"
Expand All @@ -31,8 +30,8 @@ func CaptchaVerify(app *core.App, router fiber.Router) {
return resp
}

limiter, err := common.GetLimiter[limiter.Limiter](c)
if limiter == nil {
limiter, err := common.GetLimiter(c)
if err != nil {
return err
}

Expand Down
4 changes: 2 additions & 2 deletions server/handler/comment_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type ResponseCommentCreate struct {
// @Produce json
// @Router /comments [post]
func CommentCreate(app *core.App, router fiber.Router) {
router.Post("/comments", func(c *fiber.Ctx) error {
router.Post("/comments", common.LimiterGuard(app, func(c *fiber.Ctx) error {
var p ParamsCommentCreate
if isOK, resp := common.ParamsDecode(c, &p); !isOK {
return resp
Expand Down Expand Up @@ -192,7 +192,7 @@ func CommentCreate(app *core.App, router fiber.Router) {
return common.RespData(c, ResponseCommentCreate{
CookedComment: cookedComment,
})
})
}))
}

func isAllowComment(app *core.App, c *fiber.Ctx, name string, email string, page entity.Page) (bool, error) {
Expand Down
4 changes: 2 additions & 2 deletions server/handler/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type ResponseUpload struct {
// @Failure 500 {object} Map{msg=string}
// @Router /upload [post]
func Upload(app *core.App, router fiber.Router) {
router.Post("/upload", func(c *fiber.Ctx) error {
router.Post("/upload", common.LimiterGuard(app, func(c *fiber.Ctx) error {
// 功能开关 (管理员始终开启)
if !app.Conf().ImgUpload.Enabled && !common.CheckIsAdminReq(app, c) {
return common.RespError(c, 403, i18n.T("Image upload forbidden"), common.Map{
Expand Down Expand Up @@ -196,7 +196,7 @@ func Upload(app *core.App, router fiber.Router) {
FileName: filename,
PublicURL: imgURL,
})
})
}))
}

// 调用 upgit 上传图片获得 URL
Expand Down
4 changes: 2 additions & 2 deletions server/handler/user_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type ResponseUserLogin struct {
// @Failure 500 {object} Map{msg=string}
// @Router /user/access_token [post]
func UserLogin(app *core.App, router fiber.Router) {
router.Post("/user/access_token", func(c *fiber.Ctx) error {
router.Post("/user/access_token", common.LimiterGuard(app, func(c *fiber.Ctx) error {
var p ParamsUserLogin
if isOK, resp := common.ParamsDecode(c, &p); !isOK {
return resp
Expand Down Expand Up @@ -112,5 +112,5 @@ func UserLogin(app *core.App, router fiber.Router) {
Token: jwtToken,
User: app.Dao().CookUser(&user),
})
})
}))
}
4 changes: 2 additions & 2 deletions server/handler/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type ResponseVote struct {
// @Failure 500 {object} Map{msg=string}
// @Router /votes/{type}/{target_id} [post]
func Vote(app *core.App, router fiber.Router) {
router.Post("/votes/:type/:target_id", func(c *fiber.Ctx) error {
router.Post("/votes/:type/:target_id", common.LimiterGuard(app, func(c *fiber.Ctx) error {
rawType := c.Params("type")
targetID, _ := c.ParamsInt("target_id")

Expand Down Expand Up @@ -135,5 +135,5 @@ func Vote(app *core.App, router fiber.Router) {
Up: up,
Down: down,
})
})
}))
}
18 changes: 0 additions & 18 deletions server/middleware/admin.go

This file was deleted.

Loading

0 comments on commit 570d567

Please sign in to comment.