9
9
from django import http
10
10
from django .contrib import messages
11
11
from django .contrib .contenttypes .models import ContentType
12
+ from django .core .exceptions import PermissionDenied
12
13
from django .views import generic
13
14
from django .urls import reverse
14
15
from django .utils .timezone import make_aware
@@ -33,15 +34,25 @@ def get_context_data(self,**kwargs):
33
34
34
35
package = self .get_object ()
35
36
36
- context ['filenames' ] = [(x , (self .get_object ().extracted_path / x ).is_dir ()) for x in self .get_package_filenames ()]
37
+ package_path = Path (package .extracted_path ).resolve ()
38
+
39
+ current_dir = (package_path / self .get_current_directory ()).resolve ()
40
+
41
+ # For a given path, return a triple: (path relative to package root, path relative to current directory, is a directory?)
42
+ def path_info (path ):
43
+ abspath = (package_path / path ).resolve ()
44
+ return (abspath .relative_to (package_path ), abspath .relative_to (current_dir ), abspath .is_dir ())
45
+
46
+ context ['filenames' ] = [path_info (x ) for x in self .get_package_filenames ()]
37
47
context ['editable' ] = self .package .can_be_edited_by (self .request .user )
38
48
context ['upload_file_form' ] = self .upload_file_form_class (instance = self .get_object ())
39
49
40
50
filename = self .get_filename ()
51
+
41
52
if filename is not None :
42
53
path = context ['path' ] = self .get_path ()
43
54
current_directory = context ['current_directory' ] = self .get_current_directory ().relative_to (package .extracted_path )
44
- context ['filename' ] = path . relative_to ( package . extracted_path )
55
+ context ['filename' ] = ( package_path / path ). resolve (). relative_to ( package_path )
45
56
context ['parent_directory' ] = current_directory .parent
46
57
47
58
context ['exists' ] = path .exists ()
@@ -72,10 +83,14 @@ def get_filename(self):
72
83
73
84
def get_path (self ):
74
85
package = self .get_object ()
75
- return Path (package .extracted_path ) / self .get_filename ()
86
+ package_path = Path (package .extracted_path )
87
+ path = package_path / self .get_filename ()
88
+ if not path .is_relative_to (package_path ):
89
+ raise PermissionDenied ("This file is not in the package's directory." )
90
+ return path
76
91
77
92
def get_current_directory (self ):
78
- path = self .get_path ()
93
+ path = self .get_path (). resolve ()
79
94
if path .is_dir ():
80
95
return path
81
96
else :
@@ -93,12 +108,15 @@ def __init__(self,*args,**kwargs):
93
108
super ().__init__ (* args ,** kwargs )
94
109
95
110
def dispatch (self ,request ,* args ,** kwargs ):
96
- package = self .get_object ()
111
+ package = self .package = self . get_object ()
97
112
if not package .editable :
98
113
return forbidden_response (self .request ,"This package is not editable." )
99
114
return super ().dispatch (request ,* args ,** kwargs )
100
115
101
116
def load_source (self ,path ):
117
+ if not path .resolve ().is_relative_to (self .package .extracted_path ):
118
+ raise PermissionDenied (f"This file is not in the package's directory." )
119
+
102
120
if path .is_dir ():
103
121
return None
104
122
try :
@@ -135,8 +153,14 @@ def get_context_data(self, **kwargs):
135
153
path = context ['path' ] = self .get_path ()
136
154
137
155
filenames = context ['filenames' ]
156
+
157
+ package_path = Path (package .extracted_path )
158
+
159
+ current_dir = (package_path / self .get_current_directory ()).resolve ()
160
+
138
161
if not context ['exists' ]:
139
- filenames .append ((self .get_current_directory () / filename , False ))
162
+ filenames .append ((Path (filename ), (package_path / filename ).resolve ().relative_to (current_dir ), False ))
163
+
140
164
filenames .sort ()
141
165
142
166
context ['is_binary' ] = self .is_binary
@@ -194,6 +218,9 @@ def get_success_url(self):
194
218
195
219
class AccessView (ShowPackageFilesMixin , AuthorRequiredMixin , generic .UpdateView ):
196
220
template_name = 'editable_package/access.html'
221
+
222
+ def get_filename (self ):
223
+ return None
197
224
198
225
def get_form_kwargs (self , * args , ** kwargs ):
199
226
kwargs = super ().get_form_kwargs (* args ,** kwargs )
0 commit comments