mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 10:17:17 +08:00
Add redirect and advanced settings tabs to website editor (#1267)
* Initial plan * Add redirect tab to website editor with drag-and-drop support Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> * Add advanced settings tab with rate limiting and basic auth Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> * Add htpasswd file support for basic auth (nginx and apache compatible) Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> * Fix code review issues: prevent duplicate usernames in basic auth Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> * fix: bug * fix: bug * feat: 支持real ip设置 * feat: 支持real ip设置 * fix: lint * fix: lint --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: devhaozi <115467771+devhaozi@users.noreply.github.com> Co-authored-by: 耗子 <haozi@loli.email>
This commit is contained in:
@@ -78,11 +78,21 @@ func parseRedirectFile(filePath string) (*types.Redirect, error) {
|
||||
redirectMatchPattern := regexp.MustCompile(`RedirectMatch\s+(\d+)\s+(\S+)\s+(\S+)`)
|
||||
if matches := redirectMatchPattern.FindStringSubmatch(contentStr); matches != nil {
|
||||
statusCode, _ := strconv.Atoi(matches[1])
|
||||
to := matches[3]
|
||||
keepURI := strings.Contains(to, "$1")
|
||||
if keepURI {
|
||||
to = strings.TrimSuffix(to, "$1")
|
||||
}
|
||||
// 还原 from 为简单路径格式
|
||||
from := matches[2]
|
||||
from = strings.TrimPrefix(from, "^")
|
||||
from = strings.TrimSuffix(from, "(.*)$")
|
||||
from = strings.TrimSuffix(from, "$")
|
||||
return &types.Redirect{
|
||||
Type: types.RedirectTypeURL,
|
||||
From: matches[2],
|
||||
To: matches[3],
|
||||
KeepURI: strings.Contains(matches[3], "$1"),
|
||||
From: from,
|
||||
To: to,
|
||||
KeepURI: keepURI,
|
||||
StatusCode: statusCode,
|
||||
}, nil
|
||||
}
|
||||
@@ -94,11 +104,16 @@ func parseRedirectFile(filePath string) (*types.Redirect, error) {
|
||||
if matches := hostRewritePattern.FindStringSubmatch(contentStr); matches != nil {
|
||||
statusCode, _ := strconv.Atoi(matches[3])
|
||||
host := strings.ReplaceAll(matches[1], `\.`, ".")
|
||||
to := matches[2]
|
||||
keepURI := strings.Contains(to, "$1")
|
||||
if keepURI {
|
||||
to = strings.TrimSuffix(to, "$1")
|
||||
}
|
||||
return &types.Redirect{
|
||||
Type: types.RedirectTypeHost,
|
||||
From: host,
|
||||
To: matches[2],
|
||||
KeepURI: strings.Contains(matches[2], "$1"),
|
||||
To: to,
|
||||
KeepURI: keepURI,
|
||||
StatusCode: statusCode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -541,24 +541,25 @@ func (v *baseVhost) RateLimit() *types.RateLimit {
|
||||
return nil
|
||||
}
|
||||
|
||||
rateLimit := &types.RateLimit{
|
||||
Zone: make(map[string]string),
|
||||
}
|
||||
rateLimit := &types.RateLimit{}
|
||||
|
||||
// 获取速率限制值
|
||||
rateValue := v.vhost.GetDirectiveValue("SetEnv")
|
||||
if rateValue != "" {
|
||||
rateLimit.Rate = rateValue
|
||||
// 获取速率限制值 (SetEnv rate-limit 512)
|
||||
args := v.vhost.GetDirectiveValues("SetEnv")
|
||||
if len(args) >= 2 && args[0] == "rate-limit" {
|
||||
_, _ = fmt.Sscanf(args[1], "%d", &rateLimit.Rate)
|
||||
}
|
||||
|
||||
return rateLimit
|
||||
}
|
||||
|
||||
func (v *baseVhost) SetRateLimit(limit *types.RateLimit) error {
|
||||
// 设置 mod_ratelimit
|
||||
v.vhost.SetDirective("SetOutputFilter", "RATE_LIMIT")
|
||||
if limit.Rate != "" {
|
||||
v.vhost.SetDirective("SetEnv", "rate-limit", limit.Rate)
|
||||
// Apache mod_ratelimit 只支持流量限制,不支持并发连接限制
|
||||
if limit.Rate > 0 {
|
||||
v.vhost.SetDirective("SetOutputFilter", "RATE_LIMIT")
|
||||
v.vhost.SetDirective("SetEnv", "rate-limit", fmt.Sprintf("%d", limit.Rate))
|
||||
} else {
|
||||
v.vhost.RemoveDirective("SetOutputFilter")
|
||||
v.vhost.RemoveDirectives("SetEnv")
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -606,6 +607,58 @@ func (v *baseVhost) ClearBasicAuth() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *baseVhost) RealIP() *types.RealIP {
|
||||
// Apache 使用 mod_remoteip
|
||||
// RemoteIPHeader X-Forwarded-For
|
||||
// RemoteIPTrustedProxy 127.0.0.1
|
||||
header := v.vhost.GetDirectiveValue("RemoteIPHeader")
|
||||
if header == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var from []string
|
||||
for _, dir := range v.vhost.GetDirectives("RemoteIPTrustedProxy") {
|
||||
if len(dir.Args) > 0 {
|
||||
from = append(from, dir.Args[0])
|
||||
}
|
||||
}
|
||||
|
||||
return &types.RealIP{
|
||||
From: from,
|
||||
Header: header,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *baseVhost) SetRealIP(realIP *types.RealIP) error {
|
||||
// 清除现有配置
|
||||
v.vhost.RemoveDirective("RemoteIPHeader")
|
||||
v.vhost.RemoveDirectives("RemoteIPTrustedProxy")
|
||||
|
||||
if realIP == nil || (len(realIP.From) == 0 && realIP.Header == "") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置 RemoteIPHeader
|
||||
if realIP.Header != "" {
|
||||
v.vhost.SetDirective("RemoteIPHeader", realIP.Header)
|
||||
}
|
||||
|
||||
// 设置 RemoteIPTrustedProxy
|
||||
for _, ip := range realIP.From {
|
||||
if ip != "" {
|
||||
v.vhost.AddDirective("RemoteIPTrustedProxy", ip)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *baseVhost) ClearRealIP() error {
|
||||
v.vhost.RemoveDirective("RemoteIPHeader")
|
||||
v.vhost.RemoveDirectives("RemoteIPTrustedProxy")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *baseVhost) Redirects() []types.Redirect {
|
||||
siteDir := filepath.Join(v.configDir, "site")
|
||||
redirects, _ := parseRedirectFiles(siteDir)
|
||||
|
||||
@@ -237,12 +237,13 @@ func (s *VhostTestSuite) TestRateLimit() {
|
||||
s.Nil(s.vhost.RateLimit())
|
||||
|
||||
limit := &types.RateLimit{
|
||||
Rate: "512",
|
||||
Rate: 512,
|
||||
}
|
||||
s.NoError(s.vhost.SetRateLimit(limit))
|
||||
|
||||
got := s.vhost.RateLimit()
|
||||
s.NotNil(got)
|
||||
s.Equal(512, got.Rate)
|
||||
|
||||
s.NoError(s.vhost.ClearRateLimit())
|
||||
s.Nil(s.vhost.RateLimit())
|
||||
|
||||
Reference in New Issue
Block a user