mirror of
https://github.com/vitalif/viewvc-4intranet
synced 2019-04-16 04:14:59 +03:00
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b97d2d49fa | ||
![]() |
3f43d12ee4 |
4
CHANGES
4
CHANGES
@@ -1,7 +1,3 @@
|
||||
Version 1.1.5 (released 29-Mar-2010)
|
||||
|
||||
* security fix: escape user-provided search_re input to avoid XSS attack
|
||||
|
||||
Version 1.1.4 (released 10-Mar-2010)
|
||||
|
||||
* security fix: escape user-provided query form input to avoid XSS attack
|
||||
|
@@ -15,7 +15,7 @@
|
||||
|
||||
<blockquote>
|
||||
|
||||
<p><strong>Copyright © 1999-2010 The ViewCVS Group. All rights
|
||||
<p><strong>Copyright © 1999-2009 The ViewCVS Group. All rights
|
||||
reserved.</strong></p>
|
||||
|
||||
<p>By using ViewVC, you agree to the terms and conditions set forth
|
||||
@@ -60,7 +60,6 @@
|
||||
<li>April 10, 2007 — copyright years updated</li>
|
||||
<li>February 22, 2008 — copyright years updated</li>
|
||||
<li>March 18, 2009 — copyright years updated</li>
|
||||
<li>March 29, 2010 — copyright years updated</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*-python-*-
|
||||
#
|
||||
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||
# Copyright (C) 1999-2008 The ViewCVS Group. All Rights Reserved.
|
||||
# Copyright (C) 2000 Curt Hagenlocher <curt@hagenlocher.org>
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set forth in
|
||||
@@ -32,8 +32,9 @@ import os
|
||||
import re
|
||||
import time
|
||||
import math
|
||||
import cgi
|
||||
import vclib
|
||||
import sapi
|
||||
|
||||
|
||||
re_includes = re.compile('\\#(\\s*)include(\\s*)"(.*?)"')
|
||||
|
||||
@@ -81,7 +82,7 @@ class HTMLBlameSource:
|
||||
diff_url = None
|
||||
if item.prev_rev:
|
||||
diff_url = '%sr1=%s&r2=%s' % (self.diff_url, item.prev_rev, item.rev)
|
||||
thisline = link_includes(sapi.escape(item.text), self.repos,
|
||||
thisline = link_includes(cgi.escape(item.text), self.repos,
|
||||
self.path_parts, self.include_url)
|
||||
return _item(text=thisline, line_number=item.line_number,
|
||||
rev=item.rev, prev_rev=item.prev_rev,
|
||||
|
20
lib/idiff.py
20
lib/idiff.py
@@ -1,6 +1,6 @@
|
||||
# -*-python-*-
|
||||
#
|
||||
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set forth in
|
||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||
@@ -20,7 +20,7 @@ import difflib
|
||||
import sys
|
||||
import re
|
||||
import ezt
|
||||
import sapi
|
||||
import cgi
|
||||
|
||||
def sidebyside(fromlines, tolines, context):
|
||||
"""Generate side by side diff"""
|
||||
@@ -49,18 +49,18 @@ def _mdiff_split(flag, (line_number, text)):
|
||||
while True:
|
||||
m = _re_mdiff.search(text, pos)
|
||||
if not m:
|
||||
segments.append(_item(text=sapi.escape(text[pos:]), type=None))
|
||||
segments.append(_item(text=cgi.escape(text[pos:]), type=None))
|
||||
break
|
||||
|
||||
if m.start() > pos:
|
||||
segments.append(_item(text=sapi.escape(text[pos:m.start()]), type=None))
|
||||
segments.append(_item(text=cgi.escape(text[pos:m.start()]), type=None))
|
||||
|
||||
if m.group(1) == "+":
|
||||
segments.append(_item(text=sapi.escape(m.group(2)), type="add"))
|
||||
segments.append(_item(text=cgi.escape(m.group(2)), type="add"))
|
||||
elif m.group(1) == "-":
|
||||
segments.append(_item(text=sapi.escape(m.group(2)), type="remove"))
|
||||
segments.append(_item(text=cgi.escape(m.group(2)), type="remove"))
|
||||
elif m.group(1) == "^":
|
||||
segments.append(_item(text=sapi.escape(m.group(2)), type="change"))
|
||||
segments.append(_item(text=cgi.escape(m.group(2)), type="change"))
|
||||
|
||||
pos = m.end()
|
||||
|
||||
@@ -166,12 +166,12 @@ def _differ_split(row, guide):
|
||||
|
||||
for m in _re_differ.finditer(guide, pos):
|
||||
if m.start() > pos:
|
||||
segments.append(_item(text=sapi.escape(line[pos:m.start()]), type=None))
|
||||
segments.append(_item(text=sapi.escape(line[m.start():m.end()]),
|
||||
segments.append(_item(text=cgi.escape(line[pos:m.start()]), type=None))
|
||||
segments.append(_item(text=cgi.escape(line[m.start():m.end()]),
|
||||
type="change"))
|
||||
pos = m.end()
|
||||
|
||||
segments.append(_item(text=sapi.escape(line[pos:]), type=None))
|
||||
segments.append(_item(text=cgi.escape(line[pos:]), type=None))
|
||||
|
||||
return _item(gap=ezt.boolean(gap), type=type, segments=segments,
|
||||
left_number=left_number, right_number=right_number)
|
||||
|
12
lib/query.py
12
lib/query.py
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*-python-*-
|
||||
#
|
||||
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||
# Copyright (C) 1999-2009 The ViewCVS Group. All Rights Reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set forth in
|
||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||
@@ -439,11 +439,11 @@ def main(server, cfg, viewvc_link):
|
||||
'cfg' : cfg,
|
||||
'address' : cfg.general.address,
|
||||
'vsn' : viewvc.__version__,
|
||||
'repository' : server.escape(form_data.repository),
|
||||
'branch' : server.escape(form_data.branch),
|
||||
'directory' : server.escape(form_data.directory),
|
||||
'file' : server.escape(form_data.file),
|
||||
'who' : server.escape(form_data.who),
|
||||
'repository' : server.escape(form_data.repository, 1),
|
||||
'branch' : server.escape(form_data.branch, 1),
|
||||
'directory' : server.escape(form_data.directory, 1),
|
||||
'file' : server.escape(form_data.file, 1),
|
||||
'who' : server.escape(form_data.who, 1),
|
||||
'docroot' : cfg.options.docroot is None \
|
||||
and viewvc_link + '/' + viewvc.docroot_magic_path \
|
||||
or cfg.options.docroot,
|
||||
|
33
lib/sapi.py
33
lib/sapi.py
@@ -1,6 +1,6 @@
|
||||
# -*-python-*-
|
||||
#
|
||||
# Copyright (C) 1999-2010 The ViewCVS Group. All Rights Reserved.
|
||||
# Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
|
||||
#
|
||||
# By using this file, you agree to the terms and conditions set forth in
|
||||
# the LICENSE.html file which can be found at the top level of the ViewVC
|
||||
@@ -20,7 +20,6 @@ import string
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import cgi
|
||||
|
||||
|
||||
# global server object. It will be either a CgiServer or a proxy to
|
||||
@@ -28,18 +27,6 @@ import cgi
|
||||
server = None
|
||||
|
||||
|
||||
# Simple HTML string escaping. Note that we always escape the
|
||||
# double-quote character -- ViewVC shouldn't ever need to preserve
|
||||
# that character as-is, and sometimes needs to embed escaped values
|
||||
# into HTML attributes.
|
||||
def escape(s):
|
||||
s = string.replace(s, '&', '&')
|
||||
s = string.replace(s, '>', '>')
|
||||
s = string.replace(s, '<', '<')
|
||||
s = string.replace(s, '"', """)
|
||||
return s
|
||||
|
||||
|
||||
class Server:
|
||||
def __init__(self):
|
||||
self.pageGlobals = {}
|
||||
@@ -47,9 +34,6 @@ class Server:
|
||||
def self(self):
|
||||
return self
|
||||
|
||||
def escape(self, s):
|
||||
return escape(s)
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
@@ -145,6 +129,9 @@ class CgiServer(Server):
|
||||
global server
|
||||
server = self
|
||||
|
||||
global cgi
|
||||
import cgi
|
||||
|
||||
def addheader(self, name, value):
|
||||
self.headers.append((name, value))
|
||||
|
||||
@@ -173,6 +160,9 @@ class CgiServer(Server):
|
||||
self.header(status='301 Moved')
|
||||
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)
|
||||
|
||||
def getenv(self, name, value=None):
|
||||
ret = os.environ.get(name, value)
|
||||
if self.iis and name == 'PATH_INFO' and ret:
|
||||
@@ -229,6 +219,9 @@ class AspServer(ThreadedServer):
|
||||
def redirect(self, url):
|
||||
self.response.Redirect(url)
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return self.server.HTMLEncode(str(s))
|
||||
|
||||
def getenv(self, name, value = None):
|
||||
ret = self.request.ServerVariables(name)()
|
||||
if not type(ret) is types.UnicodeType:
|
||||
@@ -290,6 +283,9 @@ class ModPythonServer(ThreadedServer):
|
||||
self.request = request
|
||||
self.headerSent = 0
|
||||
|
||||
global cgi
|
||||
import cgi
|
||||
|
||||
def addheader(self, name, value):
|
||||
self.request.headers_out.add(name, value)
|
||||
|
||||
@@ -312,6 +308,9 @@ class ModPythonServer(ThreadedServer):
|
||||
self.request.write("You are being redirected to <a href=\"%s\">%s</a>"
|
||||
% (url, url))
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return cgi.escape(s, quote)
|
||||
|
||||
def getenv(self, name, value = None):
|
||||
try:
|
||||
return self.request.subprocess_env[name]
|
||||
|
@@ -14,7 +14,7 @@
|
||||
#
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
__version__ = '1.1.5'
|
||||
__version__ = '1.1.4'
|
||||
|
||||
# this comes from our library; measure the startup time
|
||||
import debug
|
||||
@@ -24,6 +24,7 @@ debug.t_start('imports')
|
||||
# standard modules that we know are in the path or builtin
|
||||
import sys
|
||||
import os
|
||||
import cgi
|
||||
import gzip
|
||||
import mimetypes
|
||||
import re
|
||||
@@ -431,8 +432,7 @@ class Request:
|
||||
action = self.server.escape(urllib.quote(url, _URL_SAFE_CHARS))
|
||||
hidden_values = []
|
||||
for name, value in params.items():
|
||||
hidden_values.append(_item(name=self.server.escape(name),
|
||||
value=self.server.escape(value)))
|
||||
hidden_values.append(_item(name=name, value=value))
|
||||
return action, hidden_values
|
||||
|
||||
def get_link(self, view_func=None, where=None, pathtype=None, params=None):
|
||||
@@ -1075,6 +1075,9 @@ def get_file_view_info(request, where, rev=None, mime_type=None, pathrev=-1):
|
||||
revision_href=revision_href,
|
||||
prefer_markup=ezt.boolean(prefer_markup))
|
||||
|
||||
def htmlify(html):
|
||||
return html and cgi.escape(html) or html
|
||||
|
||||
|
||||
# Matches URLs
|
||||
_re_rewrite_url = re.compile('((http|https|ftp|file|svn|svn\+ssh)'
|
||||
@@ -1107,8 +1110,8 @@ class HtmlFormatter:
|
||||
"""
|
||||
s = mobj.group(0)
|
||||
trunc_s = maxlen and s[:maxlen] or s
|
||||
return '<a href="%s">%s</a>' % (sapi.escape(s),
|
||||
sapi.escape(trunc_s)), \
|
||||
return '<a href="%s">%s</a>' % (cgi.escape(s),
|
||||
cgi.escape(trunc_s)), \
|
||||
len(trunc_s)
|
||||
|
||||
def format_email(self, mobj, userdata, maxlen=0):
|
||||
@@ -1159,7 +1162,7 @@ class HtmlFormatter:
|
||||
- the number of characters returned.
|
||||
"""
|
||||
trunc_s = maxlen and s[:maxlen] or s
|
||||
return sapi.escape(trunc_s), len(trunc_s)
|
||||
return cgi.escape(trunc_s), len(trunc_s)
|
||||
|
||||
def add_formatter(self, regexp, conv, userdata=None):
|
||||
"""Register a formatter which finds instances of strings matching
|
||||
@@ -1464,7 +1467,7 @@ def copy_stream(src, dst, htmlize=0):
|
||||
if not chunk:
|
||||
break
|
||||
if htmlize:
|
||||
chunk = sapi.escape(chunk)
|
||||
chunk = htmlify(chunk)
|
||||
dst.write(chunk)
|
||||
|
||||
class MarkupPipeWrapper:
|
||||
@@ -1493,7 +1496,7 @@ def markup_stream_pygments(request, cfg, blame_data, fp, filename, mime_type):
|
||||
blame_source = []
|
||||
if blame_data:
|
||||
for i in blame_data:
|
||||
i.text = sapi.escape(i.text)
|
||||
i.text = cgi.escape(i.text)
|
||||
i.diff_href = None
|
||||
if i.prev_rev:
|
||||
i.diff_href = request.get_url(view_func=view_diff,
|
||||
@@ -1556,7 +1559,7 @@ def markup_stream_pygments(request, cfg, blame_data, fp, filename, mime_type):
|
||||
if not line:
|
||||
break
|
||||
line_no = line_no + 1
|
||||
line = sapi.escape(string.expandtabs(line, cfg.options.tabsize))
|
||||
line = cgi.escape(string.expandtabs(line, cfg.options.tabsize))
|
||||
item = vclib.Annotation(line, line_no, None, None, None, None)
|
||||
item.diff_href = None
|
||||
lines.append(item)
|
||||
@@ -2031,7 +2034,7 @@ def view_directory(request):
|
||||
'entries' : rows,
|
||||
'sortby' : sortby,
|
||||
'sortdir' : sortdir,
|
||||
'search_re' : request.server.escape(search_re),
|
||||
'search_re' : htmlify(search_re),
|
||||
'dir_pagestart' : None,
|
||||
'sortby_file_href' : request.get_url(params={'sortby': 'file',
|
||||
'sortdir': None},
|
||||
@@ -2763,7 +2766,7 @@ class DiffSource:
|
||||
hr_breakable = self.cfg.options.hr_breakable
|
||||
|
||||
# in the code below, "\x01" will be our stand-in for "&". We don't want
|
||||
# to insert "&" because it would get escaped by sapi.escape(). Similarly,
|
||||
# to insert "&" because it would get escaped by htmlify(). Similarly,
|
||||
# we use "\x02" as a stand-in for "<br>"
|
||||
|
||||
if hr_breakable > 1 and len(text) > hr_breakable:
|
||||
@@ -2773,7 +2776,7 @@ class DiffSource:
|
||||
text = string.replace(text, ' ', ' \x01nbsp;')
|
||||
else:
|
||||
text = string.replace(text, ' ', '\x01nbsp;')
|
||||
text = sapi.escape(text)
|
||||
text = htmlify(text)
|
||||
text = string.replace(text, '\x01', '&')
|
||||
text = string.replace(text, '\x02',
|
||||
'<span style="color:red">\</span><br />')
|
||||
@@ -3154,7 +3157,7 @@ def view_diff(request):
|
||||
else:
|
||||
changes = DiffSource(fp, cfg)
|
||||
else:
|
||||
raw_diff_fp = MarkupPipeWrapper(fp, request.server.escape(headers), None, 1)
|
||||
raw_diff_fp = MarkupPipeWrapper(fp, htmlify(headers), None, 1)
|
||||
|
||||
no_format_params = request.query_dict.copy()
|
||||
no_format_params['diff_format'] = None
|
||||
@@ -3701,7 +3704,7 @@ def english_query(request):
|
||||
ret.append('on all branches ')
|
||||
comment = request.query_dict.get('comment', '')
|
||||
if comment:
|
||||
ret.append('with comment <i>%s</i> ' % request.server.escape(comment))
|
||||
ret.append('with comment <i>%s</i> ' % htmlify(comment))
|
||||
if who:
|
||||
ret.append('by <em>%s</em> ' % request.server.escape(who))
|
||||
date = request.query_dict.get('date', 'hours')
|
||||
|
Reference in New Issue
Block a user