@@ -30,8 +30,29 @@ func NewFSStorage(root string) (storage Storage, err error) {
3030 return & fsStorage {root : root }, nil
3131}
3232
33+ // joinRootSafe returns filepath.Join(fs.root, key) only when key is
34+ // filepath.IsLocal, so lexical ".." segments cannot escape the storage root.
35+ func (fs * fsStorage ) joinRootSafe (key string ) (filename string , err error ) {
36+ if key == "" {
37+ return "" , errors .New ("key is required" )
38+ }
39+ if strings .Contains (key , "\x00 " ) {
40+ return "" , ErrInvalidStorageKey
41+ }
42+ k := filepath .FromSlash (strings .Trim (filepath .ToSlash (key ), "/" ))
43+ if ! filepath .IsLocal (k ) {
44+ return "" , ErrInvalidStorageKey
45+ }
46+ root := filepath .Clean (fs .root )
47+ full := filepath .Join (root , k )
48+ return full , nil
49+ }
50+
3351func (fs * fsStorage ) Stat (key string ) (stat Stat , err error ) {
34- filename := filepath .Join (fs .root , key )
52+ filename , err := fs .joinRootSafe (key )
53+ if err != nil {
54+ return nil , err
55+ }
3556 fi , err := os .Lstat (filename )
3657 if err != nil {
3758 if os .IsNotExist (err ) || strings .HasSuffix (err .Error (), "not a directory" ) {
@@ -43,7 +64,10 @@ func (fs *fsStorage) Stat(key string) (stat Stat, err error) {
4364}
4465
4566func (fs * fsStorage ) Get (key string ) (content io.ReadCloser , stat Stat , err error ) {
46- filename := filepath .Join (fs .root , key )
67+ filename , err := fs .joinRootSafe (key )
68+ if err != nil {
69+ return
70+ }
4771 file , err := os .Open (filename )
4872 if err != nil && (os .IsNotExist (err ) || strings .HasSuffix (err .Error (), "not a directory" )) {
4973 err = ErrNotFound
@@ -57,7 +81,10 @@ func (fs *fsStorage) Get(key string) (content io.ReadCloser, stat Stat, err erro
5781}
5882
5983func (fs * fsStorage ) Put (key string , content io.Reader ) (err error ) {
60- filename := filepath .Join (fs .root , key )
84+ filename , err := fs .joinRootSafe (key )
85+ if err != nil {
86+ return err
87+ }
6188 err = ensureDir (filepath .Dir (filename ))
6289 if err != nil {
6390 return
@@ -77,24 +104,44 @@ func (fs *fsStorage) Put(key string, content io.Reader) (err error) {
77104}
78105
79106func (fs * fsStorage ) Delete (key string ) (err error ) {
80- return os .Remove (filepath .Join (fs .root , key ))
107+ filename , err := fs .joinRootSafe (key )
108+ if err != nil {
109+ return err
110+ }
111+ return os .Remove (filename )
81112}
82113
83114func (fs * fsStorage ) List (prefix string ) (keys []string , err error ) {
84115 dir := strings .TrimSuffix (utils .NormalizePathname (prefix )[1 :], "/" )
85- return findFiles (filepath .Join (fs .root , dir ), dir )
116+ dir = strings .Trim (strings .TrimSpace (dir ), "/" )
117+ scanRoot := filepath .Clean (fs .root )
118+ parentKey := ""
119+ if dir != "" {
120+ var ferr error
121+ scanRoot , ferr = fs .joinRootSafe (dir )
122+ if ferr != nil {
123+ return nil , ferr
124+ }
125+ parentKey = dir
126+ }
127+ return findFiles (scanRoot , parentKey )
86128}
87129
88130func (fs * fsStorage ) DeleteAll (prefix string ) (deletedKeys []string , err error ) {
89131 dir := strings .TrimSuffix (utils .NormalizePathname (prefix )[1 :], "/" )
132+ dir = strings .Trim (strings .TrimSpace (dir ), "/" )
90133 if dir == "" {
91134 return nil , errors .New ("prefix is required" )
92135 }
93136 keys , err := fs .List (prefix )
94137 if err != nil {
95138 return
96139 }
97- err = os .RemoveAll (filepath .Join (fs .root , dir ))
140+ absDir , err := fs .joinRootSafe (dir )
141+ if err != nil {
142+ return nil , err
143+ }
144+ err = os .RemoveAll (absDir )
98145 if err != nil {
99146 return
100147 }
0 commit comments