mirror of
https://github.com/vitalif/viewvc-4intranet
synced 2019-04-16 04:14:59 +03:00
Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7bf518bc89 | ||
![]() |
74cb130fe3 | ||
![]() |
b6cedd7c1a | ||
![]() |
771d6736fb | ||
![]() |
455157e413 | ||
![]() |
c875582cfe | ||
![]() |
c3d896d5a8 | ||
![]() |
236069b068 | ||
![]() |
6de96c4fc6 | ||
![]() |
e45c2fcf6e | ||
![]() |
8c620c8c1a | ||
![]() |
c6d6dc4bdf | ||
![]() |
355fac5da1 | ||
![]() |
77d0c3dd06 | ||
![]() |
d95cb540f5 | ||
![]() |
98b757de23 | ||
![]() |
efb811d20c | ||
![]() |
a57e6b7054 | ||
![]() |
fe52bbb079 | ||
![]() |
76d6b541c3 | ||
![]() |
269a9ca864 | ||
![]() |
a5aafe3172 | ||
![]() |
d30bd89c42 | ||
![]() |
d76ce85625 | ||
![]() |
b2b247f417 | ||
![]() |
3ab2ec665b | ||
![]() |
2806f0e9a2 |
24
CHANGES
24
CHANGES
@@ -1,4 +1,21 @@
|
||||
Version 1.1.0 (released ??-???-????)
|
||||
Version 1.1.2 (released 11-Aug-2009)
|
||||
|
||||
* security fix: validate the 'view' parameter to avoid XSS attack
|
||||
* security fix: avoid printing illegal parameter names and values
|
||||
* add optional support for character encoding detection (issue #400)
|
||||
* fix username case handling in svnauthz module (issue #419)
|
||||
* fix cvsdbadmin/svnadmin rebuild error on missing repos (issue #420)
|
||||
* don't drop leading blank lines from colorized file contents (issue #422)
|
||||
* add file.ezt template logic for optionally hiding binary file contents
|
||||
|
||||
Version 1.1.1 (released 03-Jun-2009)
|
||||
|
||||
* fix broken query form (missing required template variables) (issue #416)
|
||||
* fix bug in cvsdb which caused rebuild operations to lose data (issue #417)
|
||||
* fix cvsdb purge/rebuild repos lookup to error on missing repos
|
||||
* fix misleading file contents view page title
|
||||
|
||||
Version 1.1.0 (released 13-May-2009)
|
||||
|
||||
* add support for full content diffs (issue #153)
|
||||
* make many more data dictionary items available to all views
|
||||
@@ -41,6 +58,11 @@ Version 1.1.0 (released ??-???-????)
|
||||
* fix exception in rev-sorted remote Subversion directory views (issue #409)
|
||||
* allow setting of page sizes for log and dir views individually (issue #402)
|
||||
|
||||
Version 1.0.9 (released 11-Aug-2009)
|
||||
|
||||
* security fix: validate the 'view' parameter to avoid XSS attack
|
||||
* security fix: avoid printing illegal parameter names and values
|
||||
|
||||
Version 1.0.8 (released 05-May-2009)
|
||||
|
||||
* fix directory view sorting UI
|
||||
|
@@ -177,7 +177,12 @@ if __name__ == '__main__':
|
||||
if command in ('rebuild', 'purge'):
|
||||
if quiet_level < 2:
|
||||
print "Purging existing data for repository root `%s'" % root
|
||||
db.PurgeRepository(root)
|
||||
try:
|
||||
db.PurgeRepository(root)
|
||||
except cvsdb.UnknownRepositoryError, e:
|
||||
if command == 'purge':
|
||||
sys.stderr.write("ERROR: " + str(e) + "\n")
|
||||
sys.exit(1)
|
||||
|
||||
if command in ('rebuild', 'update'):
|
||||
repository = vclib.ccvs.CVSRepository(None, rootpath, None,
|
||||
|
@@ -245,7 +245,12 @@ def main(command, repository, revs=[], verbose=0, force=0):
|
||||
if command in ('rebuild', 'purge'):
|
||||
if verbose:
|
||||
print "Purging commit info for repository root `%s'" % repository
|
||||
db.PurgeRepository(repository)
|
||||
try:
|
||||
db.PurgeRepository(repository)
|
||||
except cvsdb.UnknownRepositoryError, e:
|
||||
if command == 'purge':
|
||||
sys.stderr.write("ERROR: " + str(e) + "\n")
|
||||
sys.exit(1)
|
||||
|
||||
repo = SvnRepo(repository)
|
||||
if command == 'rebuild' or (command == 'update' and not revs):
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -315,7 +315,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">pathrev_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the revision/tag selection form.</td>
|
||||
<td>Hidden field name/value pairs for the revision/tag selection form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">pathrev_clear_action</td>
|
||||
@@ -325,7 +325,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">pathrev_clear_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the path revision clear button.</td>
|
||||
<td>Hidden field name/value pairs for the path revision clear button.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -719,7 +719,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">diff_format_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the diff format selection form.</td>
|
||||
<td>Hidden field name/value pairs for the diff format selection form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">left</td>
|
||||
@@ -899,7 +899,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">dir_paging_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the page selection form.</td>
|
||||
<td>Hidden field name/value pairs for the page selection form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">entries</td>
|
||||
@@ -1090,7 +1090,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">search_re_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the regular expression search form.</td>
|
||||
<td>Hidden field name/value pairs for the regular expression search form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">show_attic_href</td>
|
||||
@@ -1236,7 +1236,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">diff_select_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the diff selection form.</td>
|
||||
<td>Hidden field name/value pairs for the diff selection form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">entries</td>
|
||||
@@ -1517,7 +1517,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">log_paging_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the page selection form.</td>
|
||||
<td>Hidden field name/value pairs for the page selection form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">logsort</td>
|
||||
@@ -1533,7 +1533,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">logsort_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for the log sort drop down box</td>
|
||||
<td>Hidden field name/value pairs for the log sort drop down box</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">mime_type</td>
|
||||
@@ -1897,7 +1897,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">query_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for query form.</td>
|
||||
<td>Hidden field name/value pairs for query form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">querysort</td>
|
||||
@@ -2037,7 +2037,7 @@ td {
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">jump_rev_hidden_values</td>
|
||||
<td>List</td>
|
||||
<td>Hidden value name/value pairs for revision jump form.</td>
|
||||
<td>Hidden field name/value pairs for revision jump form.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">limit_changes</td>
|
||||
|
@@ -996,7 +996,7 @@ th.caption {
|
||||
<td>file query string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>file_match=FILE_MATCH</code></td>
|
||||
<td><code>file_match=<var>FILE_MATCH</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type
|
||||
of file match</td>
|
||||
@@ -1007,7 +1007,7 @@ th.caption {
|
||||
<td>author query string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>who_match=WHO_MATCH</code></td>
|
||||
<td><code>who_match=<var>WHO_MATCH</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type
|
||||
of author match</td>
|
||||
@@ -1024,36 +1024,36 @@ th.caption {
|
||||
of log message match</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>querysort=SORT</code></td>
|
||||
<td><code>querysort=<var>SORT</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"date" "author" or "file" determining order of query results</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>date=DATE</code></td>
|
||||
<td><code>date=<var>DATE</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"hours" "day" "week" "month" "all" or "explicit" to filter
|
||||
query results by date</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>hours=HOURS</code></td>
|
||||
<td><code>hours=<var>HOURS</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>number of hours back to include results from when
|
||||
<code><var>DATE</var></code> is "hours"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mindate=MINDATE</code></td>
|
||||
<td><code>mindate=<var>MINDATE</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>earliest date to include results from when
|
||||
<code><var>DATE</var></code> is "explicit"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>maxdate=MAXDATE</code></td>
|
||||
<td><code>maxdate=<var>MAXDATE</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>latest date to include results from when
|
||||
<code><var>DATE</var></code> is "explicit"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>limit_changes=LIMIT_CHANGES</code></td>
|
||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>maximum number of files to list per commit in query
|
||||
results. Default is value of <code>limit_changes</code>
|
||||
@@ -1113,7 +1113,7 @@ th.caption {
|
||||
<td>branch query string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>branch_match=BRANCH_MATCH</code></td>
|
||||
<td><code>branch_match=<var>BRANCH_MATCH</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type
|
||||
of branch match</td>
|
||||
@@ -1129,7 +1129,7 @@ th.caption {
|
||||
<td>file query string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>file_match=FILE_MATCH</code></td>
|
||||
<td><code>file_match=<var>FILE_MATCH</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type
|
||||
of file match</td>
|
||||
@@ -1140,7 +1140,7 @@ th.caption {
|
||||
<td>author query string</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>who_match=WHO_MATCH</code></td>
|
||||
<td><code>who_match=<var>WHO_MATCH</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"exact" "like" "glob" "regex" or "notregex" determining type
|
||||
of author match</td>
|
||||
@@ -1157,50 +1157,50 @@ th.caption {
|
||||
of log message match</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>querysort=SORT</code></td>
|
||||
<td><code>querysort=<var>SORT</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"date" "author" or "file" determining order of query results</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>date=DATE</code></td>
|
||||
<td><code>date=<var>DATE</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"hours" "day" "week" "month" "all" or "explicit" to filter
|
||||
query results by date</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>hours=HOURS</code></td>
|
||||
<td><code>hours=<var>HOURS</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>number of hours back to include results from when
|
||||
<code><var>DATE</var></code> is "hours"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mindate=MINDATE</code></td>
|
||||
<td><code>mindate=<var>MINDATE</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>earliest date to include results from when
|
||||
<code><var>DATE</var></code> is "explicit"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>maxdate=MAXDATE</code></td>
|
||||
<td><code>maxdate=<var>MAXDATE</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>latest date to include results from when
|
||||
<code><var>DATE</var></code> is "explicit"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>format=FORMAT</code></td>
|
||||
<td><code>format=<var>FORMAT</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>"rss" or "backout" values to generate an rss feed or list of
|
||||
commands to back out changes instead showing a normal query result
|
||||
page</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>limit=LIMIT</code></td>
|
||||
<td><code>limit=<var>LIMIT</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>maximum number of file-revisions to process during a
|
||||
query. Default is value of <code>row_limit</code> configuration
|
||||
option</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>limit_changes=LIMIT_CHANGES</code></td>
|
||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>maximum number of files to list per commit in query
|
||||
results. Default is value of <code>limit_changes</code>
|
||||
@@ -1254,7 +1254,7 @@ th.caption {
|
||||
<td><a href="#revision-param"><code>revision</code> parameter</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>limit_changes=LIMIT_CHANGES</code></td>
|
||||
<td><code>limit_changes=<var>LIMIT_CHANGES</var></code></td>
|
||||
<td>optional</td>
|
||||
<td>maximum number of files to list per commit. Default is value
|
||||
of <code>limit_changes</code> configuration option</td>
|
||||
|
@@ -244,6 +244,7 @@ class Config:
|
||||
self.options.use_localtime = 0
|
||||
self.options.short_log_len = 80
|
||||
self.options.enable_syntax_coloration = 1
|
||||
self.options.detect_encoding = 0
|
||||
self.options.use_cvsgraph = 0
|
||||
self.options.cvsgraph_conf = "cvsgraph.conf"
|
||||
self.options.use_re_search = 0
|
||||
|
24
lib/cvsdb.py
24
lib/cvsdb.py
@@ -67,9 +67,9 @@ class CheckinDatabase:
|
||||
else:
|
||||
self._version = 0
|
||||
if self._version > CURRENT_SCHEMA_VERSION:
|
||||
raise Exception("Database version %d is newer than the last "
|
||||
"version supported by this software."
|
||||
% (self._version))
|
||||
raise DatabaseVersionError("Database version %d is newer than the "
|
||||
"last version supported by this "
|
||||
"software." % (self._version))
|
||||
|
||||
def sql_get_id(self, table, column, value, auto_set):
|
||||
sql = "SELECT id FROM %s WHERE %s=%%s" % (table, column)
|
||||
@@ -542,9 +542,10 @@ class CheckinDatabase:
|
||||
cursor.execute(sql)
|
||||
|
||||
def PurgeRepository(self, repository):
|
||||
rep_id = self.GetRepositoryID(repository)
|
||||
rep_id = self.GetRepositoryID(repository, auto_set=0)
|
||||
if not rep_id:
|
||||
raise Exception, "Unknown repository '%s'" % (repository)
|
||||
raise UnknownRepositoryError("Unknown repository '%s'"
|
||||
% (repository))
|
||||
|
||||
if (self._version >= 1):
|
||||
self.sql_delete('repositories', 'id', rep_id)
|
||||
@@ -580,6 +581,19 @@ class CheckinDatabase:
|
||||
self.sql_delete('descs', 'id', checkin[3], 'descid')
|
||||
self.sql_delete('people', 'id', checkin[4], 'whoid')
|
||||
|
||||
# Reset all internal id caches. We could be choosier here,
|
||||
# but let's just be as safe as possible.
|
||||
self._get_cache = {}
|
||||
self._get_id_cache = {}
|
||||
self._desc_id_cache = {}
|
||||
|
||||
|
||||
class DatabaseVersionError(Exception):
|
||||
pass
|
||||
class UnknownRepositoryError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
## the Commit class holds data on one commit, the representation is as
|
||||
## close as possible to how it should be committed and retrieved to the
|
||||
## database engine
|
||||
|
@@ -158,8 +158,7 @@ class CgiServer(Server):
|
||||
if self.iis: url = fix_iis_url(self, url)
|
||||
self.addheader('Location', url)
|
||||
self.header(status='301 Moved')
|
||||
print 'This document is located <a href="%s">here</a>.' % url
|
||||
sys.exit(0)
|
||||
sys.stdout.write('This document is located <a href="%s">here</a>.\n' % url)
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return cgi.escape(s, quote)
|
||||
@@ -219,7 +218,6 @@ class AspServer(ThreadedServer):
|
||||
|
||||
def redirect(self, url):
|
||||
self.response.Redirect(url)
|
||||
sys.exit()
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return self.server.HTMLEncode(str(s))
|
||||
@@ -308,8 +306,7 @@ class ModPythonServer(ThreadedServer):
|
||||
self.request.headers_out['Location'] = url
|
||||
self.request.status = mod_python.apache.HTTP_MOVED_TEMPORARILY
|
||||
self.request.write("You are being redirected to <a href=\"%s\">%s</a>"
|
||||
% (url, url))
|
||||
sys.exit()
|
||||
% (url, url))
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return cgi.escape(s, quote)
|
||||
|
@@ -22,7 +22,6 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
||||
"""Subversion authz authorizer module"""
|
||||
|
||||
def __init__(self, username, params={}):
|
||||
self.username = username
|
||||
self.rootpaths = { } # {root -> { paths -> access boolean for USERNAME }}
|
||||
|
||||
# Get the authz file location from a passed-in parameter.
|
||||
@@ -32,14 +31,29 @@ class ViewVCAuthorizer(vcauth.GenericViewVCAuthorizer):
|
||||
if not os.path.exists(self.authz_file):
|
||||
raise debug.ViewVCException("Configured authzfile file not found")
|
||||
|
||||
# See if the admin wants us to do case normalization of usernames.
|
||||
self.force_username_case = params.get('force_username_case')
|
||||
if self.force_username_case == "upper":
|
||||
self.username = username.upper()
|
||||
elif self.force_username_case == "lower":
|
||||
self.username = username.lower()
|
||||
elif not self.force_username_case:
|
||||
self.username = username
|
||||
else:
|
||||
raise debug.ViewVCException("Invalid value for force_username_case "
|
||||
"option")
|
||||
|
||||
def _get_paths_for_root(self, rootname):
|
||||
if self.rootpaths.has_key(rootname):
|
||||
return self.rootpaths[rootname]
|
||||
|
||||
paths_for_root = { }
|
||||
|
||||
# Parse the authz file.
|
||||
# Parse the authz file, replacing ConfigParser's optionxform()
|
||||
# method with something that won't futz with the case of the
|
||||
# option names.
|
||||
cp = ConfigParser()
|
||||
cp.optionxform = lambda x: x
|
||||
cp.read(self.authz_file)
|
||||
|
||||
# Figure out if there are any aliases for the current username
|
||||
|
116
lib/viewvc.py
116
lib/viewvc.py
@@ -14,7 +14,7 @@
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
__version__ = '1.1-dev'
|
||||
__version__ = '1.1.2'
|
||||
|
||||
# this comes from our library; measure the startup time
|
||||
import debug
|
||||
@@ -151,6 +151,9 @@ class Request:
|
||||
|
||||
# Process the query params
|
||||
for name, values in self.server.params().items():
|
||||
# we only care about the first value
|
||||
value = values[0]
|
||||
|
||||
# patch up old queries that use 'cvsroot' to look like they used 'root'
|
||||
if name == 'cvsroot':
|
||||
name = 'root'
|
||||
@@ -161,25 +164,18 @@ class Request:
|
||||
name = 'pathrev'
|
||||
needs_redirect = 1
|
||||
|
||||
# validate the parameter
|
||||
_validate_param(name, values[0])
|
||||
# redirect view=rev to view=revision, too
|
||||
if name == 'view' and value == 'rev':
|
||||
value = 'revision'
|
||||
needs_redirect = 1
|
||||
|
||||
# Only allow the magic ViewVC MIME types (the ones used for
|
||||
# requesting the markup as as-text views) to be declared via CGI
|
||||
# params. Ignore disallowed values.
|
||||
if (name == 'content-type') and \
|
||||
(not values[0] in (viewcvs_mime_type,
|
||||
alt_mime_type,
|
||||
'text/plain')):
|
||||
continue
|
||||
# validate the parameter
|
||||
_validate_param(name, value)
|
||||
|
||||
# if we're here, then the parameter is okay
|
||||
self.query_dict[name] = values[0]
|
||||
self.query_dict[name] = value
|
||||
|
||||
# handle view parameter, redirecting old view=rev URLs to view=revision
|
||||
if self.query_dict.get('view') == 'rev':
|
||||
self.query_dict['view'] = 'revision'
|
||||
needs_redirect = 1
|
||||
# Resolve the view parameter into a handler function.
|
||||
self.view_func = _views.get(self.query_dict.get('view', None),
|
||||
self.view_func)
|
||||
|
||||
@@ -392,15 +388,14 @@ class Request:
|
||||
and self.view_func is not redirect_pathrev):
|
||||
needs_redirect = 1
|
||||
|
||||
# redirect now that we know the URL is valid
|
||||
if needs_redirect:
|
||||
self.server.redirect(self.get_url())
|
||||
|
||||
# startup is done now.
|
||||
debug.t_end('startup')
|
||||
|
||||
# Call the function for the selected view.
|
||||
self.view_func(self)
|
||||
|
||||
# If we need to redirect, do so. Otherwise, handle our requested view.
|
||||
if needs_redirect:
|
||||
self.server.redirect(self.get_url())
|
||||
else:
|
||||
self.view_func(self)
|
||||
|
||||
def get_url(self, escape=0, partial=0, prefix=0, **args):
|
||||
"""Constructs a link to another ViewVC page just like the get_link
|
||||
@@ -613,26 +608,29 @@ def _validate_param(name, value):
|
||||
this function throws an exception. Otherwise, it simply returns None.
|
||||
"""
|
||||
|
||||
# First things first -- check that we have a legal parameter name.
|
||||
try:
|
||||
validator = _legal_params[name]
|
||||
except KeyError:
|
||||
raise debug.ViewVCException(
|
||||
'An illegal parameter name ("%s") was passed.' % name,
|
||||
'An illegal parameter name was provided.',
|
||||
'400 Bad Request')
|
||||
|
||||
# Is there a validator? Is it a regex or a function? Validate if
|
||||
# we can, returning without incident on valid input.
|
||||
if validator is None:
|
||||
return
|
||||
elif hasattr(validator, 'match'):
|
||||
if validator.match(value):
|
||||
return
|
||||
else:
|
||||
if validator(value):
|
||||
return
|
||||
|
||||
# is the validator a regex?
|
||||
if hasattr(validator, 'match'):
|
||||
if not validator.match(value):
|
||||
raise debug.ViewVCException(
|
||||
'An illegal value ("%s") was passed as a parameter.' %
|
||||
value, '400 Bad Request')
|
||||
return
|
||||
|
||||
# the validator must be a function
|
||||
validator(value)
|
||||
# If we get here, the input value isn't valid.
|
||||
raise debug.ViewVCException(
|
||||
'An illegal value was provided for the "%s" parameter.' % (name),
|
||||
'400 Bad Request')
|
||||
|
||||
def _validate_regex(value):
|
||||
# hmm. there isn't anything that we can do here.
|
||||
@@ -642,17 +640,23 @@ def _validate_regex(value):
|
||||
### parameters could constitute a CSS attack.
|
||||
pass
|
||||
|
||||
def _validate_view(value):
|
||||
# Return true iff VALUE is one of our allowed views.
|
||||
return _views.has_key(value)
|
||||
|
||||
def _validate_mimetype(value):
|
||||
# For security purposes, we only allow mimetypes from a predefined set
|
||||
# thereof.
|
||||
return value in (viewcvs_mime_type, alt_mime_type, 'text/plain')
|
||||
|
||||
# obvious things here. note that we don't need uppercase for alpha.
|
||||
_re_validate_alpha = re.compile('^[a-z]+$')
|
||||
_re_validate_number = re.compile('^[0-9]+$')
|
||||
_re_validate_boolint = re.compile('^[01]$')
|
||||
|
||||
# when comparing two revs, we sometimes construct REV:SYMBOL, so ':' is needed
|
||||
_re_validate_revnum = re.compile('^[-_.a-zA-Z0-9:~\\[\\]/]*$')
|
||||
|
||||
# it appears that RFC 2045 also says these chars are legal: !#$%&'*+^{|}~`
|
||||
# but woah... I'll just leave them out for now
|
||||
_re_validate_mimetype = re.compile('^[-_.a-zA-Z0-9/]+$')
|
||||
|
||||
# date time values
|
||||
_re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d'
|
||||
'(:\d\d)?)?)?$')
|
||||
@@ -660,12 +664,12 @@ _re_validate_datetime = re.compile(r'^(\d\d\d\d-\d\d-\d\d(\s+\d\d:\d\d'
|
||||
# the legal query parameters and their validation functions
|
||||
_legal_params = {
|
||||
'root' : None,
|
||||
'view' : None,
|
||||
'view' : _validate_view,
|
||||
'search' : _validate_regex,
|
||||
'p1' : None,
|
||||
'p2' : None,
|
||||
|
||||
'hideattic' : _re_validate_number,
|
||||
'hideattic' : _re_validate_boolint,
|
||||
'limit_changes' : _re_validate_number,
|
||||
'sortby' : _re_validate_alpha,
|
||||
'sortdir' : _re_validate_alpha,
|
||||
@@ -676,13 +680,13 @@ _legal_params = {
|
||||
'log_pagestart' : _re_validate_number,
|
||||
'annotate' : _re_validate_revnum,
|
||||
'graph' : _re_validate_revnum,
|
||||
'makeimage' : _re_validate_number,
|
||||
'makeimage' : _re_validate_boolint,
|
||||
'r1' : _re_validate_revnum,
|
||||
'tr1' : _re_validate_revnum,
|
||||
'r2' : _re_validate_revnum,
|
||||
'tr2' : _re_validate_revnum,
|
||||
'revision' : _re_validate_revnum,
|
||||
'content-type' : _re_validate_mimetype,
|
||||
'content-type' : _validate_mimetype,
|
||||
|
||||
# for query
|
||||
'branch' : _validate_regex,
|
||||
@@ -709,10 +713,10 @@ _legal_params = {
|
||||
'orig_view' : None,
|
||||
|
||||
# deprecated
|
||||
'parent' : _re_validate_number,
|
||||
'parent' : _re_validate_boolint,
|
||||
'rev' : _re_validate_revnum,
|
||||
'tarball' : _re_validate_number,
|
||||
'hidecvsroot' : _re_validate_number,
|
||||
'tarball' : _re_validate_boolint,
|
||||
'hidecvsroot' : _re_validate_boolint,
|
||||
}
|
||||
|
||||
def _path_join(path_parts):
|
||||
@@ -1362,11 +1366,22 @@ def markup_stream_pygments(request, cfg, blame_data, fp, filename, mime_type):
|
||||
get_lexer_by_name, \
|
||||
get_lexer_for_mimetype, \
|
||||
get_lexer_for_filename
|
||||
encoding = 'guess'
|
||||
if cfg.options.detect_encoding:
|
||||
try:
|
||||
import chardet
|
||||
encoding = 'chardet'
|
||||
except (SyntaxError, ImportError):
|
||||
pass
|
||||
try:
|
||||
lexer = get_lexer_for_mimetype(mime_type)
|
||||
lexer = get_lexer_for_mimetype(mime_type,
|
||||
encoding=encoding,
|
||||
stripnl=False)
|
||||
except ClassNotFound:
|
||||
try:
|
||||
lexer = get_lexer_for_filename(filename)
|
||||
lexer = get_lexer_for_filename(filename,
|
||||
encoding=encoding,
|
||||
stripnl=False)
|
||||
except ClassNotFound:
|
||||
use_pygments = 0
|
||||
except ImportError:
|
||||
@@ -3425,6 +3440,8 @@ def view_queryform(request):
|
||||
'hours' : request.query_dict.get('hours', '2'),
|
||||
'mindate' : request.query_dict.get('mindate', ''),
|
||||
'maxdate' : request.query_dict.get('maxdate', ''),
|
||||
'query_action' : query_action,
|
||||
'query_hidden_values' : query_hidden_values,
|
||||
'limit_changes' : limit_changes,
|
||||
'dir_href' : request.get_url(view_func=view_directory, params={},
|
||||
escape=1),
|
||||
@@ -4068,10 +4085,9 @@ def view_error(server, cfg):
|
||||
exc_dict = debug.GetExceptionData()
|
||||
status = exc_dict['status']
|
||||
if exc_dict['msg']:
|
||||
exc_dict['msg'] = htmlify(exc_dict['msg'], mangle_email_addrs=0)
|
||||
exc_dict['msg'] = server.escape(exc_dict['msg'])
|
||||
if exc_dict['stacktrace']:
|
||||
exc_dict['stacktrace'] = htmlify(exc_dict['stacktrace'],
|
||||
mangle_email_addrs=0)
|
||||
exc_dict['stacktrace'] = server.escape(exc_dict['stacktrace'])
|
||||
handled = 0
|
||||
|
||||
# use the configured error template if possible
|
||||
|
@@ -1,5 +1,15 @@
|
||||
[# ------------------------------------------------------------------------- ]
|
||||
[# CUSTOMIZE ME: To avoid displaying "binary garbage" -- the contents of ]
|
||||
[# files with non-human-readable file formats -- change the value of the ]
|
||||
[# hide_binary_garbage variable below to 1. ]
|
||||
[# ------------------------------------------------------------------------- ]
|
||||
|
||||
[define hide_binary_garbage]0[end]
|
||||
|
||||
[# ------------------------------------------------------------------------- ]
|
||||
|
||||
[# setup page definitions]
|
||||
[define page_title]Annotate of /[where][end]
|
||||
[define page_title]Contents of /[where][end]
|
||||
[define help_href][docroot]/help_rootview.html[end]
|
||||
[# end]
|
||||
|
||||
@@ -57,6 +67,14 @@ Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong><
|
||||
[end]
|
||||
</div>
|
||||
|
||||
[if-any prefer_markup][define hide_binary_garbage]0[end][end]
|
||||
[if-any image_src_href][define hide_binary_garbage]0[end][end]
|
||||
|
||||
[is hide_binary_garbage "1"]
|
||||
<p><strong>This file's contents are not viewable. Please
|
||||
<a href="[download_href]">download</a> this version of the
|
||||
file in order to view it.</strong></p>
|
||||
[else]
|
||||
|
||||
[define last_rev]0[end]
|
||||
[define rowclass]vc_row_even[end]
|
||||
@@ -99,6 +117,7 @@ Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong><
|
||||
</div>
|
||||
[end]
|
||||
[end]
|
||||
[end]
|
||||
|
||||
[include "include/props.ezt"]
|
||||
[include "include/footer.ezt"]
|
||||
|
Reference in New Issue
Block a user