@@ -6,18 +6,18 @@ import (
66 "strings"
77
88 "github.com/OpenListTeam/OpenList/v4/internal/conf"
9- "github.com/OpenListTeam/OpenList/v4/internal/task"
10-
119 "github.com/OpenListTeam/OpenList/v4/internal/errs"
1210 "github.com/OpenListTeam/OpenList/v4/internal/fs"
1311 "github.com/OpenListTeam/OpenList/v4/internal/model"
1412 "github.com/OpenListTeam/OpenList/v4/internal/op"
1513 "github.com/OpenListTeam/OpenList/v4/internal/sign"
14+ "github.com/OpenListTeam/OpenList/v4/internal/task"
1615 "github.com/OpenListTeam/OpenList/v4/pkg/generic"
1716 "github.com/OpenListTeam/OpenList/v4/pkg/utils"
1817 "github.com/OpenListTeam/OpenList/v4/server/common"
1918 "github.com/gin-gonic/gin"
2019 "github.com/pkg/errors"
20+ log "github.com/sirupsen/logrus"
2121)
2222
2323type MkdirOrLinkReq struct {
@@ -80,36 +80,44 @@ func FsMove(c *gin.Context) {
8080 common .ErrorResp (c , errs .PermissionDenied , 403 )
8181 return
8282 }
83- srcDir , err := user .JoinPath (req .SrcDir )
84- if err != nil {
85- common .ErrorResp (c , err , 403 )
86- return
87- }
8883 dstDir , err := user .JoinPath (req .DstDir )
8984 if err != nil {
9085 common .ErrorResp (c , err , 403 )
9186 return
9287 }
9388
94- var validNames []string
95- if ! req .Overwrite {
96- for _ , name := range req .Names {
97- if res , _ := fs .Get (c .Request .Context (), stdpath .Join (dstDir , name ), & fs.GetArgs {NoLog : true }); res != nil && ! req .SkipExisting {
98- common .ErrorStrResp (c , fmt .Sprintf ("file [%s] exists" , name ), 403 )
89+ validPaths := make ([]string , 0 , len (req .Names ))
90+ for _ , name := range req .Names {
91+ // ensure req.Names is not a relative path
92+ srcPath := stdpath .Join (req .SrcDir , name )
93+ srcPath , err = user .JoinPath (srcPath )
94+ if err != nil {
95+ common .ErrorResp (c , err , 403 )
96+ return
97+ }
98+ if ! req .Overwrite {
99+ base := stdpath .Base (srcPath )
100+ if base == "." || base == "/" {
101+ common .ErrorStrResp (c , fmt .Sprintf ("invalid file name [%s]" , name ), 400 )
99102 return
100- } else if res == nil {
101- validNames = append (validNames , name )
103+ }
104+ if res , _ := fs .Get (c .Request .Context (), stdpath .Join (dstDir , base ), & fs.GetArgs {NoLog : true }); res != nil {
105+ if ! req .SkipExisting {
106+ common .ErrorStrResp (c , fmt .Sprintf ("file [%s] exists" , name ), 403 )
107+ return
108+ } else {
109+ continue
110+ }
102111 }
103112 }
104- } else {
105- validNames = req .Names
113+ validPaths = append (validPaths , srcPath )
106114 }
107115
108116 // Create all tasks immediately without any synchronous validation
109117 // All validation will be done asynchronously in the background
110118 var addedTasks []task.TaskExtensionInfo
111- for i , name := range validNames {
112- t , err := fs .Move (c .Request .Context (), stdpath . Join ( srcDir , name ), dstDir , len (validNames ) > i + 1 )
119+ for i , p := range validPaths {
120+ t , err := fs .Move (c .Request .Context (), p , dstDir , len (validPaths ) > i + 1 )
113121 if t != nil {
114122 addedTasks = append (addedTasks , t )
115123 }
@@ -147,44 +155,48 @@ func FsCopy(c *gin.Context) {
147155 common .ErrorResp (c , errs .PermissionDenied , 403 )
148156 return
149157 }
150- srcDir , err := user .JoinPath (req .SrcDir )
151- if err != nil {
152- common .ErrorResp (c , err , 403 )
153- return
154- }
155158 dstDir , err := user .JoinPath (req .DstDir )
156159 if err != nil {
157160 common .ErrorResp (c , err , 403 )
158161 return
159162 }
160163
161- var validNames []string
162- if ! req .Overwrite {
163- for _ , name := range req .Names {
164- if res , _ := fs .Get (c .Request .Context (), stdpath .Join (dstDir , name ), & fs.GetArgs {NoLog : true }); res != nil {
164+ validPaths := make ([]string , 0 , len (req .Names ))
165+ for _ , name := range req .Names {
166+ // ensure req.Names is not a relative path
167+ srcPath := stdpath .Join (req .SrcDir , name )
168+ srcPath , err = user .JoinPath (srcPath )
169+ if err != nil {
170+ common .ErrorResp (c , err , 403 )
171+ return
172+ }
173+ if ! req .Overwrite {
174+ base := stdpath .Base (srcPath )
175+ if base == "." || base == "/" {
176+ common .ErrorStrResp (c , fmt .Sprintf ("invalid file name [%s]" , name ), 400 )
177+ return
178+ }
179+ if res , _ := fs .Get (c .Request .Context (), stdpath .Join (dstDir , base ), & fs.GetArgs {NoLog : true }); res != nil {
165180 if ! req .SkipExisting && ! req .Merge {
166181 common .ErrorStrResp (c , fmt .Sprintf ("file [%s] exists" , name ), 403 )
167182 return
168- } else if req .Merge && res .IsDir () {
169- validNames = append ( validNames , name )
183+ } else if ! req .Merge || ! res .IsDir () {
184+ continue
170185 }
171- } else {
172- validNames = append (validNames , name )
173186 }
174187 }
175- } else {
176- validNames = req .Names
188+ validPaths = append (validPaths , srcPath )
177189 }
178190
179191 // Create all tasks immediately without any synchronous validation
180192 // All validation will be done asynchronously in the background
181193 var addedTasks []task.TaskExtensionInfo
182- for i , name := range validNames {
194+ for i , p := range validPaths {
183195 var t task.TaskExtensionInfo
184196 if req .Merge {
185- t , err = fs .Merge (c .Request .Context (), stdpath . Join ( srcDir , name ), dstDir , len (validNames ) > i + 1 )
197+ t , err = fs .Merge (c .Request .Context (), p , dstDir , len (validPaths ) > i + 1 )
186198 } else {
187- t , err = fs .Copy (c .Request .Context (), stdpath . Join ( srcDir , name ), dstDir , len (validNames ) > i + 1 )
199+ t , err = fs .Copy (c .Request .Context (), p , dstDir , len (validPaths ) > i + 1 )
188200 }
189201 if t != nil {
190202 addedTasks = append (addedTasks , t )
@@ -276,18 +288,25 @@ func FsRemove(c *gin.Context) {
276288 common .ErrorResp (c , errs .PermissionDenied , 403 )
277289 return
278290 }
279- reqDir , err := user .JoinPath (req .Dir )
280- if err != nil {
281- common .ErrorResp (c , err , 403 )
282- return
283- }
284- for _ , name := range req .Names {
285- // Skip invalid item names (empty string, whitespace, ".", "/","\t\t","..") to prevent accidental removal of current directory
291+ for i , name := range req .Names {
286292 if strings .TrimSpace (utils .FixAndCleanPath (name )) == "/" {
287- utils .Log .Warnf ("FsRemove: invalid item skipped: %s (parent directory: %s)\n " , name , reqDir )
293+ log .Warnf ("FsRemove: invalid item skipped: %s (parent directory: %s)\n " , name , req .Dir )
294+ req .Names [i ] = ""
295+ continue
296+ }
297+ // ensure req.Names is not a relative path
298+ var err error
299+ req .Names [i ], err = user .JoinPath (stdpath .Join (req .Dir , name ))
300+ if err != nil {
301+ common .ErrorResp (c , err , 403 )
302+ return
303+ }
304+ }
305+ for _ , path := range req .Names {
306+ if path == "" {
288307 continue
289308 }
290- err := fs .Remove (c .Request .Context (), stdpath . Join ( reqDir , name ) )
309+ err := fs .Remove (c .Request .Context (), path )
291310 if err != nil {
292311 common .ErrorResp (c , err , 500 )
293312 return
0 commit comments