104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
package ipblock
|
||
|
||
import (
|
||
"net/http"
|
||
"time"
|
||
|
||
"91porn-server/app/appg"
|
||
"91porn-server/common"
|
||
"91porn-server/common/constant"
|
||
"91porn-server/common/constant/redisconst"
|
||
"91porn-server/common/stderr"
|
||
"91porn-server/models/v/ipblockmod"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
func IPBlock(blockType string) gin.HandlerFunc {
|
||
return func(ctx *gin.Context) {
|
||
if !appg.ShouldEnforceIPRateLimit() {
|
||
return
|
||
}
|
||
ip := common.GetIP(ctx)
|
||
key := redisconst.IPBlockKey(blockType)
|
||
if count, err := appg.Redis.SCard(key); count == 0 || err != nil {
|
||
ipdata, err := ipblockmod.AggregateForIPArray(blockType)
|
||
if err == nil && len(ipdata.IPS) > 0 {
|
||
// 仅在集合为空时回源重建:直接 SAdd,去掉 Del 以消除"先删后加"的空窗期漏拦;
|
||
// TTL 设在 key 自身(此前误用 IPBlockKey(key) 二次包裹成 ip:block:ip:block:xxx,
|
||
// 导致真实集合永不过期、永不回源刷新)
|
||
_, _ = appg.Redis.SAdd(key, ipdata.IPS)
|
||
_, _ = appg.Redis.ExpireKey(key, redisconst.IPBlockExpire)
|
||
}
|
||
}
|
||
isBlock, err := appg.Redis.SISMember(key, ip)
|
||
//表示当前IP在限制名单中
|
||
if isBlock && err == nil {
|
||
ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||
"code": stderr.ErrReqForbidden,
|
||
"msg": stderr.ErrReqForbidden.Msg(),
|
||
"tip": stderr.ErrReqForbidden.Tip(),
|
||
})
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
func IPAutoBlock(blockType string, duration time.Duration, count int64) gin.HandlerFunc {
|
||
return func(ctx *gin.Context) {
|
||
if !appg.ShouldEnforceIPRateLimit() {
|
||
return
|
||
}
|
||
ip := common.GetIP(ctx)
|
||
if ip != "" {
|
||
key := redisconst.IPAutoBlockKey(blockType, ip)
|
||
cnt := appg.Redis.Incr(key)
|
||
if cnt == 1 {
|
||
_, _ = appg.Redis.ExpireKey(key, duration)
|
||
}
|
||
if cnt >= count {
|
||
switch blockType {
|
||
case constant.Register:
|
||
ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||
"code": stderr.ErrLoginTooFrequently,
|
||
"msg": stderr.ErrLoginTooFrequently.Msg(),
|
||
"tip": stderr.ErrLoginTooFrequently.Tip(),
|
||
})
|
||
default:
|
||
ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
|
||
"code": stderr.ErrReqForbidden,
|
||
"msg": stderr.ErrReqForbidden.Msg(),
|
||
"tip": stderr.ErrReqForbidden.Tip(),
|
||
})
|
||
}
|
||
return
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func CountAutoBlock(blockType string, duration time.Duration, count int64) gin.HandlerFunc {
|
||
return func(ctx *gin.Context) {
|
||
var key string
|
||
switch blockType {
|
||
case constant.BlockComment:
|
||
uid, err := common.GetUID(ctx)
|
||
if err == nil {
|
||
key = redisconst.AutoBlockKey(blockType, uid)
|
||
}
|
||
}
|
||
cnt := appg.Redis.Incr(key)
|
||
if cnt == 1 {
|
||
_, _ = appg.Redis.ExpireKey(key, duration)
|
||
}
|
||
if cnt > count {
|
||
ctx.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{
|
||
"code": stderr.ErrReqForbidden,
|
||
"msg": stderr.ErrReqForbidden.Msg(),
|
||
"tip": stderr.ErrReqForbidden.Tip(),
|
||
})
|
||
return
|
||
}
|
||
}
|
||
}
|