Commits

Anonymous committed da1d7a1

0.12.3dev: Added validations for a wiki page name to create, rename and import.
Closes #10274.

Comments (0)

Files changed (6)

trac/wiki/admin.py

 from trac.admin import *
 from trac.core import *
 from trac.wiki import model
-from trac.wiki.api import WikiSystem
+from trac.wiki.api import WikiSystem, validate_page_name
 from trac.util import read_file
 from trac.util.compat import any
 from trac.util.datefmt import format_datetime, from_utimestamp, \
     
     def import_page(self, filename, title, create_only=[],
                     replace=False):
+        if not validate_page_name(title):
+            raise AdminCommandError(_("Invalid Wiki page name '%(name)s'",
+                                      name=title))
         if filename:
             if not os.path.isfile(filename):
                 raise AdminCommandError(_("'%(name)s' is not a file",
             return
         if not new_name:
             raise AdminCommandError(_('A new name is mandatory for a rename.'))
+        if not validate_page_name(new_name):
+            raise AdminCommandError(_("The new name is invalid."))
         @self.env.with_transaction()
         def do_rename(db):
             if model.WikiPage(self.env, new_name, db=db).exists:
 from trac.config import BoolOption, ListOption
 from trac.core import *
 from trac.resource import IResourceManager
+from trac.util.compat import all
 from trac.util.translation import _
 from trac.wiki.parser import WikiParser
 
     return largs, kwargs
 
 
+def validate_page_name(pagename):
+    """Utility for validating wiki page name.
+
+    :param pagename: wiki page name to validate
+    """
+    return pagename and \
+           all(part not in ('', '.', '..') for part in pagename.split('/'))
+
+
 class WikiSystem(Component):
     """Wiki system manager."""
 

trac/wiki/model.py

 from trac.resource import Resource
 from trac.util.datefmt import from_utimestamp, to_utimestamp, utc
 from trac.util.translation import _
-from trac.wiki.api import WikiSystem
+from trac.wiki.api import WikiSystem, validate_page_name
 
 
 class WikiPage(object):
                     listener.wiki_page_version_deleted(self)
 
     def save(self, author, comment, remote_addr, t=None, db=None):
+        if not validate_page_name(self.name):
+            raise TracError(_("Invalid Wiki page name '%(name)s'",
+                              name=self.name))
+
         new_text = self.text != self.old_text
         if not new_text and self.readonly == self.old_readonly:
             raise TracError(_('Page not modified'))
         """
         assert self.exists, 'Cannot rename non-existent page'
 
+        if not validate_page_name(new_name):
+            raise TracError(_("Invalid Wiki page name '%(name)s'",
+                              name=new_name))
         old_name = self.name
         
         @self.env.with_transaction()

trac/wiki/tests/functional.py

         tc.submit('submit')
         tc.url(page_url)
         tc.find("A new name is mandatory for a rename")
+        # attempt to rename the page to an invalid page name
+        tc.formvalue('rename-form', 'new_name', '../WikiStart')
+        tc.submit('submit')
+        tc.url(page_url)
+        tc.find("The new name is invalid")
         # attempt to rename the page to the current page name       
         tc.formvalue('rename-form', 'new_name', pagename)
         tc.submit('submit')
         tc.find('"123"')
 
 
+class RegressionTestTicket10274(FunctionalTwillTestCaseSetup):
+    def runTest(self):
+        """Test for regression of http://trac.edgewall.org/ticket/10274"""
+        self._tester.go_to_wiki('WikiStart/..')
+        tc.find("Invalid Wiki page name 'WikiStart/..'")
+        self._tester.go_to_wiki('../WikiStart')
+        tc.find("Invalid Wiki page name '../WikiStart'")
+        self._tester.go_to_wiki('WikiStart/./SubPage')
+        tc.find("Invalid Wiki page name 'WikiStart/./SubPage'")
+
+
 def functionalSuite(suite=None):
     if not suite:
         import trac.tests.functional.testcases
     suite.addTest(TestWiki())
     suite.addTest(TestWikiRename())
     suite.addTest(RegressionTestTicket4812())
+    suite.addTest(RegressionTestTicket10274())
     if has_docutils:
         import docutils
         if get_pkginfo(docutils):

trac/wiki/tests/model.py

         listener = TestWikiChangeListener(self.env)
         self.assertEqual((page, 'TestPage'), listener.renamed[0])
 
+    def test_invalid_page_name(self):
+        invalid_names = ('../Page', 'Page/..', 'Page/////SubPage',
+                         'Page/./SubPage', '/PagePrefix', 'PageSuffix/')
+
+        for name in invalid_names:
+            page = WikiPage(self.env)
+            page.name = name
+            page.text = 'Bla bla'
+            t = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
+            self.assertRaises(TracError, page.save, 'joe', 'Testing', '::1', t)
+
+        page = WikiPage(self.env)
+        page.name = 'TestPage'
+        page.text = 'Bla bla'
+        t = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
+        page.save('joe', 'Testing', '::1', t)
+        for name in invalid_names:
+            page = WikiPage(self.env, 'TestPage')
+            self.assertRaises(TracError, page.rename, name)
+
 
 def suite():
     return unittest.makeSuite(WikiPageTestCase, 'test')

trac/wiki/web_ui.py

                             add_stylesheet, add_warning, prevnext_nav, \
                             Chrome, INavigationContributor, ITemplateProvider
 from trac.web.api import IRequestHandler
-from trac.wiki.api import IWikiPageManipulator, WikiSystem
+from trac.wiki.api import IWikiPageManipulator, WikiSystem, validate_page_name
 from trac.wiki.formatter import format_to, OneLinerFormatter
 from trac.wiki.model import WikiPage
  
         version = req.args.get('version')
         old_version = req.args.get('old_version')
 
-        if pagename.endswith('/'):
-            req.redirect(req.href.wiki(pagename.strip('/')))
+        if pagename.startswith('/') or pagename.endswith('/') or \
+                '//' in pagename:
+            pagename = re.sub(r'/{2,}', '/', pagename.strip('/'))
+            req.redirect(req.href.wiki(pagename))
+        if not validate_page_name(pagename):
+            raise TracError(_("Invalid Wiki page name '%(name)s'",
+                              name=pagename))
 
         page = WikiPage(self.env, pagename)
         versioned_page = WikiPage(self.env, pagename, version=version)
             req.redirect(get_resource_url(self.env, page.resource, req.href))
  	 
         old_name, old_version = page.name, page.version
-        new_name = req.args.get('new_name', '').rstrip('/')
+        new_name = req.args.get('new_name', '')
+        new_name = re.sub(r'/{2,}', '/', new_name.strip('/'))
         redirect = req.args.get('redirect')
  	 
         # verify input parameters
         warn = None
         if not new_name:
             warn = _('A new name is mandatory for a rename.')
+        elif not validate_page_name(new_name):
+            warn = _("The new name is invalid (a name which is separated "
+                     "with slashes cannot be '.' or '..').")
         elif new_name == old_name:
             warn = _('The new name must be different from the old name.')
         elif WikiPage(self.env, new_name).exists: