mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 03:07:20 +08:00
feat: 支持cidr,close #764
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-rat/utils/str"
|
||||
@@ -144,7 +144,26 @@ func (r userTokenRepo) ValidateReq(req *http.Request) (uint, error) {
|
||||
if err != nil {
|
||||
ip = req.RemoteAddr
|
||||
}
|
||||
if !slices.Contains(userToken.IPs, ip) {
|
||||
allowed := false
|
||||
requestIP := net.ParseIP(ip)
|
||||
if requestIP != nil {
|
||||
for _, allowedIP := range userToken.IPs {
|
||||
if strings.Contains(allowedIP, "/") {
|
||||
// CIDR
|
||||
if _, ipNet, err := net.ParseCIDR(allowedIP); err == nil && ipNet.Contains(requestIP) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// IP
|
||||
if allowedIP == ip {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
return 0, errors.New(r.t.Get("invalid request ip: %s", ip))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +47,30 @@ func Entrance(t *gotext.Locale, conf *koanf.Koanf, session *sessions.Manager) fu
|
||||
if err != nil {
|
||||
ip = r.RemoteAddr
|
||||
}
|
||||
if len(conf.Strings("http.bind_ip")) > 0 && !slices.Contains(conf.Strings("http.bind_ip"), ip) {
|
||||
Abort(w, http.StatusTeapot, t.Get("invalid request ip: %s", ip))
|
||||
return
|
||||
if len(conf.Strings("http.bind_ip")) > 0 {
|
||||
allowed := false
|
||||
requestIP := net.ParseIP(ip)
|
||||
if requestIP != nil {
|
||||
for _, allowedIP := range conf.Strings("http.bind_ip") {
|
||||
if strings.Contains(allowedIP, "/") {
|
||||
// CIDR
|
||||
if _, ipNet, err := net.ParseCIDR(allowedIP); err == nil && ipNet.Contains(requestIP) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// IP
|
||||
if allowedIP == ip {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
Abort(w, http.StatusTeapot, t.Get("invalid request ip: %s", ip))
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(conf.Strings("http.bind_ua")) > 0 && !slices.Contains(conf.Strings("http.bind_ua"), r.UserAgent()) {
|
||||
Abort(w, http.StatusTeapot, t.Get("invalid request user agent: %s", r.UserAgent()))
|
||||
|
||||
@@ -25,7 +25,7 @@ type SettingPanel struct {
|
||||
func (r *SettingPanel) Rules(_ *http.Request) map[string]string {
|
||||
return map[string]string{
|
||||
"BindDomain.*": "required",
|
||||
"BindIP.*": "required|ip",
|
||||
"BindIP.*": "required|ipcidr",
|
||||
"BindUA.*": "required",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type UserTokenCreate struct {
|
||||
|
||||
func (r *UserTokenCreate) Rules(_ *http.Request) map[string]string {
|
||||
return map[string]string{
|
||||
"IPs.*": "required|ip",
|
||||
"IPs.*": "required|ipcidr",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,6 @@ type UserTokenUpdate struct {
|
||||
|
||||
func (r *UserTokenUpdate) Rules(_ *http.Request) map[string]string {
|
||||
return map[string]string{
|
||||
"IPs.*": "required|ip",
|
||||
"IPs.*": "required|ipcidr",
|
||||
}
|
||||
}
|
||||
|
||||
22
internal/http/rule/ip_cidr.go
Normal file
22
internal/http/rule/ip_cidr.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package rule
|
||||
|
||||
import "net"
|
||||
|
||||
// IPCIDR 验证一个值是否是一个有效的 IP 或 CIDR 格式
|
||||
type IPCIDR struct{}
|
||||
|
||||
func NewIPCIDR() *IPCIDR {
|
||||
return &IPCIDR{}
|
||||
}
|
||||
|
||||
func (r *IPCIDR) Passes(val any, options ...any) bool {
|
||||
if str, ok := val.(string); ok {
|
||||
if ip := net.ParseIP(str); ip != nil {
|
||||
return true // 是有效的 IP
|
||||
}
|
||||
if _, _, err := net.ParseCIDR(str); err == nil {
|
||||
return true // 是有效的 CIDR
|
||||
}
|
||||
}
|
||||
return false // 既不是 IP 也不是 CIDR
|
||||
}
|
||||
@@ -11,11 +11,13 @@ func GlobalRules(db *gorm.DB) {
|
||||
"notExists": NewNotExists(db).Passes,
|
||||
"password": NewPassword().Passes,
|
||||
"cron": NewCron().Passes,
|
||||
"ipcidr": NewIPCIDR().Passes,
|
||||
})
|
||||
validate.AddGlobalMessages(map[string]string{
|
||||
"exists": "{field} 不存在",
|
||||
"notExists": "{field} 已存在",
|
||||
"password": "密码不满足要求(8-20位,至少包含字母、数字、特殊字符中的两种)",
|
||||
"cron": "Cron 表达式不合法",
|
||||
"ipcidr": "IP 或 CIDR 格式不合法",
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user