view MoinMoin/action/SubscribeUser.py @ 5910:7e7e1cbb9d3f

security: fix remote code execution vulnerability in twikidraw/anywikidraw actions We have wikiutil.taintfilename() to make user supplied filenames safe, so that they can't contain any "special" characters like path separators, etc. It is used at many places in moin, but wasn't used here. :|
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 29 Dec 2012 15:05:29 +0100
parents c16381dd17fe
children
line wrap: on
line source
"""
   MoinMoin - Subscribeuser - Action
   Subscribe (or unsubscribe) a user to a page.

   @copyright: 2003 Daniela Nicklas <nicklas@informatik.uni-stuttgart.de>,
               2005 MoinMoin:AlexanderSchremmer,
               2009 MoinMoin:ThomasWaldmann
   @license: GNU GPL, see COPYING for details.
"""

import sys, os, re

from MoinMoin.Page import Page
from MoinMoin import user
from MoinMoin import wikiutil


def show_form(pagename, request):
    _ = request.getText
    request.theme.send_title(_("Subscribe users to the page %s") % pagename, pagename=pagename)

    request.write("""
<form action="%s" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="SubscribeUser">
%s <input type="text" name="users" size="50">
<input type="submit" value="Subscribe">
</form>
""" % (request.href(pagename),
      _("Enter user names (comma separated):")))
    request.theme.send_footer(pagename)
    request.theme.send_closing_html()


def parse_re(usernames):
    username_regexes = []
    for name in usernames:
        if name.startswith("re:"):
            name = name[3:]
        else:
            name = re.escape(name)
        username_regexes.append(name)
    return username_regexes


def parse_userlist(usernames):
    subscribe = []
    unsubscribe = []
    for name in usernames:
        if name.startswith("-"):
            unsubscribe.append(name[1:])
        elif name.startswith("+"):
            subscribe.append(name[1:])
        else:
            subscribe.append(name)
    return parse_re(subscribe), parse_re(unsubscribe)


def show_result(pagename, request):
    _ = request.getText

    request.theme.send_title(_("Subscribed for %s:") % pagename, pagename=pagename)

    from MoinMoin.formatter.text_html import Formatter
    formatter = Formatter(request)

    usernames = request.form['users'].split(",")
    subscribe, unsubscribe = parse_userlist(usernames)

    result = subscribe_users(request, subscribe, unsubscribe, pagename, formatter)
    request.write(result)

    request.theme.send_footer(pagename)
    request.theme.send_closing_html()


def subscribe_users(request, subscribe, unsubscribe, pagename, formatter):
    _ = request.getText

    if not Page(request, pagename).exists():
        return u"Page does not exist."

    result = []
    did_match = {}

    # get user object - only with IDs!
    for userid in user.getUserList(request):
        userobj = user.User(request, userid)
        name = userobj.name

        matched = subscribed = False

        for name_re in unsubscribe:
            if re.match(name_re, name, re.U):
                matched = did_match[name_re] = True
                if (not userobj.isSubscribedTo([pagename]) or
                    userobj.unsubscribe(pagename)):
                    subscribed = False
                break

        for name_re in subscribe:
            if re.match(name_re, name, re.U):
                matched = did_match[name_re] = True
                if (userobj.isSubscribedTo([pagename]) or
                    (userobj.email or userobj.jid) and userobj.subscribe(pagename)):
                    subscribed = True
                break

        if matched:
            result.extend([formatter.smiley(subscribed and '{*}' or '{o}'),
                           formatter.text(" "),
                           formatter.url(1, Page(request, name).url(request)),
                           formatter.text(name),
                           formatter.url(0),
                           formatter.linebreak(preformatted=0),
                          ])

    result.extend([''.join([formatter.smiley('{X}'),
                            formatter.text(" " + _("Not a user:") + " " + name_re),
                            formatter.linebreak(preformatted=0)])
                   for name_re in subscribe + unsubscribe if name_re not in did_match])

    return ''.join(result)


def execute(pagename, request):
    _ = request.getText
    if not request.user.may.admin(pagename):
        thispage = Page(request, pagename)
        request.theme.add_msg(_("You are not allowed to perform this action."), "error")
        return thispage.send_page()
    elif 'users' not in request.form:
        show_form(pagename, request)
    else:
        show_result(pagename, request)


if __name__ == '__main__':
    args = sys.argv
    if len(args) < 2:
        print >>sys.stderr, """Subscribe users

%(myname)s pagename [+|-][re:]username[,username[,username[,...]]] [URL]

+username: subscribes user <username> to page <pagename>.
-username: unsubscribes user <username> from page <pagename>.
+re:username_re: subscribes users who match <username_re> regex.
-re:username_re: unsubscribes users who match <username_re> regex.

URL is just needed for a farmconfig scenario.

Example:
%(myname)s FrontPage TestUser,MatthewSimpson

""" % {"myname": os.path.basename(args[0])}
        raise SystemExit

    pagename = args[1]
    usernames = args[2].split(",")

    if len(args) > 3:
        request_url = args[3]
    else:
        request_url = None

    # Setup MoinMoin environment
    from MoinMoin.web.contexts import ScriptContext
    request = ScriptContext(url=request_url)

    from MoinMoin.formatter.text_plain import Formatter
    formatter = Formatter(request)

    subscribe, unsubscribe = parse_userlist(usernames)

    print subscribe_users(request, subscribe, unsubscribe, pagename, formatter)