summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Archiver/Archiver.py4
-rw-r--r--Mailman/Cgi/edithtml.py10
-rw-r--r--Mailman/Cgi/private.py2
-rw-r--r--Mailman/Cgi/wsgi_app.py40
-rw-r--r--Mailman/MailList.py7
5 files changed, 52 insertions, 11 deletions
diff --git a/Mailman/Archiver/Archiver.py b/Mailman/Archiver/Archiver.py
index f76992928..96d6c46dc 100644
--- a/Mailman/Archiver/Archiver.py
+++ b/Mailman/Archiver/Archiver.py
@@ -136,15 +136,13 @@ class Archiver:
def GetBaseArchiveURL(self):
if self.archive_private:
- url = self.GetScriptURL('private')
+ url = self.GetScriptURL('private') + '/index.html'
else:
web_host = config.domains.get(self.host_name, self.host_name)
url = config.PUBLIC_ARCHIVE_URL % {
'listname': self.internal_name(),
'hostname': web_host,
}
- if not url.endswith('/'):
- url += '/'
return url
def __archive_file(self, afn):
diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py
index b0275de75..7a16c1c28 100644
--- a/Mailman/Cgi/edithtml.py
+++ b/Mailman/Cgi/edithtml.py
@@ -27,9 +27,11 @@ from Mailman import Errors
from Mailman import i18n
from Mailman import MailList
from Mailman import Utils
+from Mailman import Defaults
from Mailman.Cgi import Auth
from Mailman.htmlformat import *
from Mailman.HTMLFormatter import HTMLFormatter
+from Mailman.configuration import config
_ = i18n._
@@ -54,8 +56,8 @@ def main():
doc = Document()
# Set up the system default language
- i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
- doc.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
+ i18n.set_language(config.DEFAULT_SERVER_LANGUAGE)
+ doc.set_language(config.DEFAULT_SERVER_LANGUAGE)
parts = Utils.GetPathPieces()
if not parts:
@@ -82,8 +84,8 @@ def main():
cgidata = cgi.FieldStorage()
# Editing the html for a list is limited to the list admin and site admin.
- if not mlist.WebAuthenticate((mm_cfg.AuthListAdmin,
- mm_cfg.AuthSiteAdmin),
+ if not mlist.WebAuthenticate((Defaults.AuthListAdmin,
+ Defaults.AuthSiteAdmin),
cgidata.getvalue('adminpw', '')):
if cgidata.has_key('admlogin'):
# This is a re-authorization attempt
diff --git a/Mailman/Cgi/private.py b/Mailman/Cgi/private.py
index c9e69944b..1ed6fa23d 100644
--- a/Mailman/Cgi/private.py
+++ b/Mailman/Cgi/private.py
@@ -139,7 +139,7 @@ def main():
print 'Content-type: text/html; charset=' + charset + '\n\n'
# Put the original full path in the authorization form, but avoid
# trailing slash if we're not adding parts. We add it below.
- action = mlist.GetScriptURL('private', absolute=1)
+ action = mlist.GetScriptURL('private')
if parts[1:]:
action = os.path.join(action, SLASH.join(parts[1:]))
# If we added '/index.html' to true_filename, add a slash to the URL.
diff --git a/Mailman/Cgi/wsgi_app.py b/Mailman/Cgi/wsgi_app.py
index 8e77352d6..402745e3b 100644
--- a/Mailman/Cgi/wsgi_app.py
+++ b/Mailman/Cgi/wsgi_app.py
@@ -16,8 +16,10 @@
# USA.
import os
+import re
import sys
+from urlparse import urlparse
from cStringIO import StringIO
from email import message_from_string
@@ -25,6 +27,9 @@ from Mailman.configuration import config
# XXX Should this be configurable in Defaults.py?
STEALTH_MODE = False
+MOVED_RESPONSE = '302 Found'
+# Above is for debugging convenience. We should use:
+# MOVED_RESPONSE = '301 Moved Permanently'
@@ -35,11 +40,15 @@ def websafe(s):
SCRIPTS = ['admin', 'admindb', 'confirm', 'create',
'edithtml', 'listinfo', 'options', 'private',
'rmlist', 'roster', 'subscribe']
+ARCHVIEW = ['private']
SLASH = '/'
NL2 = '\n\n'
CRLF2 = '\r\n\r\n'
+dotonly = re.compile(r'^\.+$')
+
+SCRIPT_BASE = urlparse(config.DEFAULT_URL_PATTERN)[2]
# WSGI to CGI wrapper. Mostly copied from scripts/driver.
@@ -62,11 +71,40 @@ def mailman_app(environ, start_response):
path = environ['PATH_INFO']
paths = path.split(SLASH)
+ # sanity check for paths
+ spaths = [ i for i in paths[1:] if i and not dotonly.match(i) ]
+ # Do some path mangling here because someone may access with
+ # trailing slash for script. (Eg., /mailman/listinfo/ ->
+ # /mailman/listinfo) Use of SCRIPT_BASE breaks relative
+ # URI principle but we do believe mailman WSGI should NOT exposed
+ # to the Internet.
+ if spaths != paths[1:]:
+ if path == SLASH:
+ newpath = SCRIPT_BASE + 'listinfo'
+ else:
+ # Sanitize URI by spaths
+ if paths[1] not in ARCHVIEW:
+ newpath = SCRIPT_BASE + SLASH.join(spaths)
+ else:
+ # 'private' is different because, if trailing slash is
+ # present, it silently redirecte to index.html.
+ # Let's make it explicit here.
+ newpath = SCRIPT_BASE + SLASH.join(spaths) + '/index.html'
+ start_response(MOVED_RESPONSE, [('Location', newpath)])
+ return 'Location: ' + newpath
script = paths[1]
if script in SCRIPTS:
environ['SCRIPT_NAME'] = script
if len(paths) > 2:
- environ['PATH_INFO'] = SLASH + SLASH.join(paths[2:])
+ path_info = SLASH + SLASH.join(paths[2:])
+ if script in ARCHVIEW \
+ and len(paths) in (3,4) \
+ and not paths[-1].split('.')[-1] in ('html', 'txt', 'gz'):
+ # /private/listname or /private/listname/YYYYmm
+ newpath = SCRIPT_BASE + SLASH.join(spaths) + '/index.html'
+ start_response(MOVED_RESPONSE, [('Location', newpath)])
+ return 'Location: ' + newpath
+ environ['PATH_INFO'] = path_info
else:
environ['PATH_INFO'] = ''
# Reverse proxy environment.
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index 245f16ad8..555717eff 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -263,8 +263,11 @@ class MailList(HTMLFormatter, Deliverer, ListAdmin,
acct, host = tuple(member.split('@'))
return "%s%s@%s" % (acct, self.umbrella_member_suffix, host)
- def GetScriptURL(self, target):
- return Utils.ScriptURL(target) + '/' + self.fqdn_listname
+ def GetScriptURL(self, target, absolute=False):
+ if absolute:
+ return self.web_page_url + target + '/' + self.fqdn_listname
+ else:
+ return Utils.ScriptURL(target) + '/' + self.fqdn_listname
def GetOptionsURL(self, user, obscure=False, absolute=False):
url = self.GetScriptURL('options', absolute)