Skip to content

Commit 506ff1d

Browse files
authored
fix: preserve custom rewrite template name case (#12714)
* refactor: enhance rewrite configuration handling by introducing safe name validation and custom rewrite existence checks * test: cover custom rewrite name handling
1 parent c3b7dee commit 506ff1d

2 files changed

Lines changed: 108 additions & 14 deletions

File tree

agent/app/service/website_rewrite.go

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,16 @@ func (w WebsiteService) GetRewriteConfig(req request.NginxRewriteReq) (*response
7070
}
7171
}
7272
} else {
73-
rewriteFile := fmt.Sprintf("rewrite/%s.conf", strings.ToLower(req.Name))
74-
contentByte, _ = nginx_conf.Rewrites.ReadFile(rewriteFile)
75-
if contentByte == nil {
76-
customRewriteDir := GetOpenrestyDir(DefaultRewriteDir)
77-
safeName := path.Base(req.Name)
78-
if safeName != req.Name || strings.Contains(safeName, "..") {
79-
return nil, buserr.New("ErrInvalidParams")
80-
}
81-
customRewriteFile := path.Join(customRewriteDir, fmt.Sprintf("%s.conf", strings.ToLower(req.Name)))
73+
safeName, err := getSafeRewriteName(req.Name)
74+
if err != nil {
75+
return nil, err
76+
}
77+
customRewriteFile := path.Join(GetOpenrestyDir(DefaultRewriteDir), fmt.Sprintf("%s.conf", safeName))
78+
if files.NewFileOp().Stat(customRewriteFile) {
8279
contentByte, err = files.NewFileOp().GetContent(customRewriteFile)
80+
} else {
81+
rewriteFile := fmt.Sprintf("rewrite/%s.conf", strings.ToLower(safeName))
82+
contentByte, _ = nginx_conf.Rewrites.ReadFile(rewriteFile)
8383
}
8484
}
8585
return &response.NginxRewriteRes{
@@ -95,14 +95,18 @@ func (w WebsiteService) OperateCustomRewrite(req request.CustomRewriteOperate) e
9595
return err
9696
}
9797
}
98-
safeName := path.Base(req.Name)
99-
if safeName != req.Name || strings.Contains(safeName, "..") {
100-
return buserr.New("ErrInvalidParams")
98+
safeName, err := getSafeRewriteName(req.Name)
99+
if err != nil {
100+
return err
101101
}
102-
rewriteFile := path.Join(rewriteDir, fmt.Sprintf("%s.conf", req.Name))
102+
rewriteFile := path.Join(rewriteDir, fmt.Sprintf("%s.conf", safeName))
103103
switch req.Operate {
104104
case "create":
105-
if fileOp.Stat(rewriteFile) {
105+
exist, err := customRewriteNameExist(rewriteDir, safeName)
106+
if err != nil {
107+
return err
108+
}
109+
if exist || builtinRewriteNameExist(safeName) {
106110
return buserr.New("ErrNameIsExist")
107111
}
108112
return fileOp.WriteFile(rewriteFile, strings.NewReader(req.Content), constant.DirPerm)
@@ -112,6 +116,37 @@ func (w WebsiteService) OperateCustomRewrite(req request.CustomRewriteOperate) e
112116
return nil
113117
}
114118

119+
func getSafeRewriteName(name string) (string, error) {
120+
safeName := path.Base(name)
121+
if safeName != name || strings.Contains(safeName, "..") {
122+
return "", buserr.New("ErrInvalidParams")
123+
}
124+
return safeName, nil
125+
}
126+
127+
func builtinRewriteNameExist(name string) bool {
128+
rewriteFile := fmt.Sprintf("rewrite/%s.conf", strings.ToLower(name))
129+
contentByte, _ := nginx_conf.Rewrites.ReadFile(rewriteFile)
130+
return contentByte != nil
131+
}
132+
133+
func customRewriteNameExist(rewriteDir, name string) (bool, error) {
134+
entries, err := os.ReadDir(rewriteDir)
135+
if err != nil {
136+
return false, err
137+
}
138+
for _, entry := range entries {
139+
if entry.IsDir() {
140+
continue
141+
}
142+
entryName := strings.TrimSuffix(entry.Name(), ".conf")
143+
if strings.EqualFold(entryName, name) {
144+
return true, nil
145+
}
146+
}
147+
return false, nil
148+
}
149+
115150
func (w WebsiteService) ListCustomRewrite() ([]string, error) {
116151
rewriteDir := GetOpenrestyDir(DefaultRewriteDir)
117152
fileOp := files.NewFileOp()
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package service
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func TestBuiltinRewriteNameExistIgnoresCase(t *testing.T) {
9+
if !builtinRewriteNameExist("WordPress") {
10+
t.Fatal("expected WordPress to match builtin wordpress rewrite")
11+
}
12+
if !builtinRewriteNameExist("EmpireCMS") {
13+
t.Fatal("expected EmpireCMS to match builtin empirecms rewrite")
14+
}
15+
if builtinRewriteNameExist("not-exist-rewrite") {
16+
t.Fatal("expected unknown rewrite name to be absent")
17+
}
18+
}
19+
20+
func TestCustomRewriteNameExistIgnoresCase(t *testing.T) {
21+
rewriteDir := t.TempDir()
22+
if err := os.WriteFile(rewriteDir+"/MyRewrite.conf", []byte("content"), 0644); err != nil {
23+
t.Fatal(err)
24+
}
25+
26+
tests := []struct {
27+
name string
28+
want bool
29+
}{
30+
{name: "MyRewrite", want: true},
31+
{name: "myrewrite", want: true},
32+
{name: "MYREWRITE", want: true},
33+
{name: "OtherRewrite", want: false},
34+
}
35+
36+
for _, tt := range tests {
37+
t.Run(tt.name, func(t *testing.T) {
38+
got, err := customRewriteNameExist(rewriteDir, tt.name)
39+
if err != nil {
40+
t.Fatal(err)
41+
}
42+
if got != tt.want {
43+
t.Fatalf("customRewriteNameExist() = %v, want %v", got, tt.want)
44+
}
45+
})
46+
}
47+
}
48+
49+
func TestGetSafeRewriteName(t *testing.T) {
50+
if _, err := getSafeRewriteName("../rewrite"); err == nil {
51+
t.Fatal("expected path traversal name to be rejected")
52+
}
53+
if _, err := getSafeRewriteName("rewrite/name"); err == nil {
54+
t.Fatal("expected path separator name to be rejected")
55+
}
56+
if name, err := getSafeRewriteName("MyRewrite"); err != nil || name != "MyRewrite" {
57+
t.Fatalf("getSafeRewriteName() = %q, %v; want MyRewrite, nil", name, err)
58+
}
59+
}

0 commit comments

Comments
 (0)