ERepublik & OEIS & Redmine: Fix possible denial of service via memory exhaustion (with %(thing)999999999999s for instance).

master
Valentin Lorentz 2013-05-22 22:14:24 +02:00
parent 77cbf1e5b3
commit 7844cacd77
5 changed files with 33 additions and 24 deletions

View File

@ -31,6 +31,8 @@
import re
import json
from string import Template
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
@ -84,7 +86,8 @@ class ERepublik(callbacks.Plugin):
Returns informations about a citizen with advanced formating."""
citizen = flatten_subdicts(getCitizen(irc, name))
try:
irc.replies(map(lambda x:x%citizen, format_.split('\\n')))
repl = lambda x:Template(x).safe_substitute(citizen)
irc.replies(map(repl, format_.split('\\n')))
except KeyError:
raise
irc.error(_('Invalid format.'), Raise=True)
@ -99,10 +102,10 @@ class ERepublik(callbacks.Plugin):
%s""" % doc
return wrap(f, ['text'], name=name)
info = _gen("""Name: %(name)s (ID: %(id)s), Level: %(level)s, Strength:
%(strength)s, Residence: %(residence__country__name)s, Citizenship:
%(citizenship__name)s, Rank: %(rank__name)s, Party: %(party__name)s, MU:
%(army__name)s.
info = _gen("""Name: $name (ID: $id), Level: $level, Strength:
$strength, Residence: $residence__country__name, Citizenship:
$citizenship__name, Rank: $rank__name, Party: $party__name, MU:
$army__name.
""",
'info',
'Returns general informations about a citizen.')

View File

@ -28,6 +28,8 @@
###
from string import Template
import supybot.log as log
import supybot.utils as utils
from supybot.commands import *
@ -62,7 +64,8 @@ class OEIS(callbacks.Plugin):
except ParseError:
irc.error(_('Could not parse OEIS answer.'), Raise=True)
if results:
irc.reply(format('%L', map(lambda x:format_ % x, results)))
repl = Template(format_).safe_substitute
irc.reply(format('%L', map(repl, results)))
else:
irc.reply(_('No entry matches this sequence.'))
advsearch = wrap(_advsearch, ['something', 'somethingWithoutSpaces'])
@ -75,7 +78,7 @@ class OEIS(callbacks.Plugin):
%s""" % doc
return wrap(f, ['somethingWithoutSpaces'], name=name)
names = _gen('%(name)s (%(id)s)', 'names',
names = _gen('$name ($id)', 'names',
'Return names of matching entries.')

View File

@ -39,8 +39,8 @@ class OEISTestCase(PluginTestCase):
self.assertRegexp('names 15454454651,198448,228454456', 'No entry')
def testAdvsearch(self):
self.assertRegexp('advsearch "%(id)s" 1,2,6,24,120', 'A000142')
self.assertNotRegexp('advsearch "%(id)s" 1,2,6,24,120', 'factorial')
self.assertRegexp('advsearch "$id" 1,2,6,24,120', 'A000142')
self.assertNotRegexp('advsearch "$id" 1,2,6,24,120', 'factorial')
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

View File

@ -56,22 +56,22 @@ conf.registerChannelValue(Redmine, 'defaultsite',
registry.String('', _("""Default site for this channel.""")))
conf.registerGroup(Redmine, 'format')
conf.registerChannelValue(Redmine.format, 'projects',
registry.String('%(name)s (%(identifier)s)',
registry.String('$name ($identifier)',
_("""Format of projects displayed by @projects.""")))
conf.registerChannelValue(Redmine.format, 'issues',
registry.String('\x02#%(id)i: %(subject)s\x02 (last update: '
'%(updated_on)s / status: %(status__name)s)',
registry.String('\x02#$id)i: $subject\x02 (last update: '
'$updated_on / status: $status__name)',
_("""Format of issues displayed by @issues.""")))
conf.registerChannelValue(Redmine.format, 'issue',
registry.String('\x02#%(id)i (%(status__name)s)\x02: \x02%(subject)s\x02 '
'in \x02%(project__name)s\x02 (%(project__id)i). Created by '
'\x02%(author__name)s\x02 (%(author__id)i) on \x02%(created_on)s\x02, '
'last updated on \x02%(updated_on)s',
registry.String('\x02#$id)i ($status__name)\x02: \x02$subject\x02 '
'in \x02$project__name\x02 ($project__id)i). Created by '
'\x02$author__name\x02 ($author__id)i) on \x02$created_on\x02, '
'last updated on \x02$updated_on',
_("""Format of issues displayed by @issue.""")))
conf.registerGroup(Redmine.format, 'announces')
conf.registerChannelValue(Redmine.format.announces, 'issue',
registry.String('Updated issue: \x02#%(id)i (%(status__name)s)\x02: '
'\x02%(subject)s\x02 in \x02%(project__name)s\x02 (%(project__id)i).',
registry.String('Updated issue: \x02#$id)i ($status__name)\x02: '
'\x02$subject\x02 in \x02$project__name\x02 ($project__id)i).',
_("""Format of issues displayed by @issue.""")))
conf.registerGroup(Redmine, 'announce')

View File

@ -31,6 +31,7 @@
import sys
import json
import time
from string import Template
import supybot.conf as conf
import supybot.utils as utils
@ -189,7 +190,8 @@ class Redmine(callbacks.Plugin):
format_ = self.registryValue('format.announces.issue',
channel)
for issue in announces:
s = format_ % flatten_subdicts(issue)
repl = flatten_subdicts(issue)
s = Template(format_).safe_substitute(repl)
if sys.version_info[0] < 3:
s = s.encode('utf8', errors='replace')
msg = ircmsgs.privmsg(channel, s)
@ -255,8 +257,8 @@ class Redmine(callbacks.Plugin):
"""
Return the list of projects of the Redmine <site>."""
projects = map(lambda x:self.registryValue('format.projects') % x,
fetch(site, 'projects')['projects'])
repl = Template(self.registryValue('format.projects')).safe_substitute
projects = map(repl, fetch(site, 'projects')['projects'])
irc.reply(format('%L', projects))
@internationalizeDocstring
@ -285,8 +287,8 @@ class Redmine(callbacks.Plugin):
new_issues = []
for issue in issues:
new_issues.append(flatten_subdicts(issue))
issues = map(lambda x:self.registryValue('format.issues') % x,
new_issues)
repl = Template(self.registryValue('format.issues')).safe_substitute
issues = map(repl, new_issues)
irc.reply(format('%L', issues))
@internationalizeDocstring
@ -298,7 +300,8 @@ class Redmine(callbacks.Plugin):
try:
issue = fetch(site, 'issues/%i' % issueid)['issue']
issue = flatten_subdicts(issue)
irc.reply(self.registryValue('format.issue') % issue)
irc.reply(Template(self.registryValue('format.issue')) \
.safe_substitute(issue))
except ResourceNotFound:
irc.error(_('Issue not found.'), Raise=True)
except KeyError as e: