Ticket #9511: 9511-repository-dir-prefix-r10018.patch
| File 9511-repository-dir-prefix-r10018.patch, 7.1 KB (added by rblank, 21 months ago) |
|---|
-
trac/util/__init__.py
diff --git a/trac/util/__init__.py b/trac/util/__init__.py
a b 341 341 copytree_rec(str_path(src), str_path(dst)) 342 342 343 343 344 def is_path_below(path, parent): 345 """Return True iff `path` is equal to parent or is located below `parent` 346 at any level. 347 """ 348 path = os.path.abspath(path) 349 parent = os.path.abspath(parent) 350 return path == parent or path.startswith(parent + os.sep) 351 352 344 353 # -- sys utils 345 354 346 355 def arity(f): -
trac/util/tests/__init__.py
diff --git a/trac/util/tests/__init__.py b/trac/util/tests/__init__.py
a b 80 80 self.assertEqual('test content', util.read_file(self.path)) 81 81 82 82 83 class PathTestCase(unittest.TestCase): 84 85 def assert_below(self, path, parent): 86 self.assert_(util.is_path_below(path.replace('/', os.sep), 87 parent.replace('/', os.sep))) 88 89 def assert_not_below(self, path, parent): 90 self.assert_(not util.is_path_below(path.replace('/', os.sep), 91 parent.replace('/', os.sep))) 92 93 def test_is_path_below(self): 94 self.assert_below('/svn/project1', '/svn/project1') 95 self.assert_below('/svn/project1/repos', '/svn/project1') 96 self.assert_below('/svn/project1/sub/repos', '/svn/project1') 97 self.assert_below('/svn/project1/sub/../repos', '/svn/project1') 98 self.assert_not_below('/svn/project2/repos', '/svn/project1') 99 self.assert_not_below('/svn/project2/sub/repos', '/svn/project1') 100 self.assert_not_below('/svn/project1/../project2/repos', 101 '/svn/project1') 102 self.assert_(util.is_path_below('repos', os.path.join(os.getcwd()))) 103 self.assert_(not util.is_path_below('../sub/repos', 104 os.path.join(os.getcwd()))) 105 106 83 107 class ContentDispositionTestCase(unittest.TestCase): 84 108 85 109 def test_filename(self): … … 96 120 def suite(): 97 121 suite = unittest.TestSuite() 98 122 suite.addTest(unittest.makeSuite(AtomicFileTestCase, 'test')) 123 suite.addTest(unittest.makeSuite(PathTestCase, 'test')) 99 124 suite.addTest(unittest.makeSuite(ContentDispositionTestCase, 'test')) 100 125 suite.addTest(concurrency.suite()) 101 126 suite.addTest(datefmt.suite()) -
trac/versioncontrol/admin.py
diff --git a/trac/versioncontrol/admin.py b/trac/versioncontrol/admin.py
a b 11 11 # individuals. For the exact contribution history, see the revision 12 12 # history and logs, available at http://trac.edgewall.org/. 13 13 14 import os.path 14 15 import sys 15 16 16 17 from genshi.builder import tag 17 18 18 19 from trac.admin import IAdminCommandProvider, IAdminPanelProvider 19 from trac.config import _TRUE_VALUES 20 from trac.config import _TRUE_VALUES, ListOption 20 21 from trac.core import * 21 22 from trac.perm import IPermissionRequestor 23 from trac.util import is_path_below 22 24 from trac.util.text import breakable_path, normalize_whitespace, print_table, \ 23 25 printout 24 26 from trac.util.translation import _, ngettext, tag_ … … 164 166 165 167 implements(IAdminPanelProvider) 166 168 169 repository_dir_prefixes = ListOption('trac', 'repository_dir_prefixes', '', 170 doc="""Comma-separated list of allowed prefixes for repository 171 directories when adding and editing repositories in the repository 172 admin panel. If the list is empty, all repository directories are 173 allowed. (''since 0.12.1'')""") 174 167 175 # IAdminPanelProvider methods 168 176 169 177 def get_admin_panels(self, req): … … 198 206 if (value is not None or field == 'hidden') \ 199 207 and value != info.get(field): 200 208 changes[field] = value 209 if 'dir' in changes \ 210 and not self._check_dir(req, changes['dir']): 211 changes = {} 201 212 if changes: 202 213 db_provider.modify_repository(reponame, changes) 203 214 add_notice(req, _('Your changes have been saved.')) … … 222 233 'hook to call %(cset_added)s with the new ' 223 234 'repository name.', cset_added=cset_added) 224 235 add_notice(req, msg) 225 req.redirect(req.href.admin(category, page)) 236 if changes: 237 req.redirect(req.href.admin(category, page)) 226 238 227 239 Chrome(self.env).add_wiki_toolbars(req) 228 240 data = {'view': 'detail', 'reponame': reponame} … … 234 246 if db_provider and req.args.get('add_repos'): 235 247 name = req.args.get('name') 236 248 type_ = req.args.get('type') 237 dir = req.args.get('dir') 238 if name is not None and type_ is not None and dir: 239 # Avoid errors when copy/pasting paths 240 dir = normalize_whitespace(dir) 249 # Avoid errors when copy/pasting paths 250 dir = normalize_whitespace(req.args.get('dir', '')) 251 prefixes = [os.path.join(self.env.path, prefix) 252 for prefix in self.repository_dir_prefixes] 253 if name is None or type_ is None or not dir: 254 add_warning(req, _('Missing arguments to add a ' 255 'repository.')) 256 elif self._check_dir(req, dir): 241 257 db_provider.add_repository(name, dir, type_) 242 258 name = name or '(default)' 243 259 add_notice(req, _('The repository "%(name)s" has been ' … … 256 272 cset_added=cset_added) 257 273 add_notice(req, msg) 258 274 req.redirect(req.href.admin(category, page)) 259 add_warning(req, _('Missing arguments to add a '260 'repository.'))261 275 262 276 # Add a repository alias 263 277 elif db_provider and req.args.get('add_alias'): … … 319 333 except Exception: 320 334 pass 321 335 return info 336 337 def _check_dir(self, req, dir): 338 """Check that a repository directory is valid, and add a warning 339 message if not. 340 """ 341 if not os.path.isabs(dir): 342 add_warning(req, _('The repository directory must be an absolute ' 343 'path.')) 344 return False 345 prefixes = [os.path.join(self.env.path, prefix) 346 for prefix in self.repository_dir_prefixes] 347 if prefixes and not any(is_path_below(dir, prefix) 348 for prefix in prefixes): 349 add_warning(req, _('The repository directory must be located ' 350 'below one of the following directories: ' 351 '%(dirs)s', dirs=', '.join(prefixes))) 352 return False 353 return True
