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

View File

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

View File

@ -39,8 +39,8 @@ class OEISTestCase(PluginTestCase):
self.assertRegexp('names 15454454651,198448,228454456', 'No entry') self.assertRegexp('names 15454454651,198448,228454456', 'No entry')
def testAdvsearch(self): def testAdvsearch(self):
self.assertRegexp('advsearch "%(id)s" 1,2,6,24,120', 'A000142') self.assertRegexp('advsearch "$id" 1,2,6,24,120', 'A000142')
self.assertNotRegexp('advsearch "%(id)s" 1,2,6,24,120', 'factorial') self.assertNotRegexp('advsearch "$id" 1,2,6,24,120', 'factorial')
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: # 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."""))) registry.String('', _("""Default site for this channel.""")))
conf.registerGroup(Redmine, 'format') conf.registerGroup(Redmine, 'format')
conf.registerChannelValue(Redmine.format, 'projects', conf.registerChannelValue(Redmine.format, 'projects',
registry.String('%(name)s (%(identifier)s)', registry.String('$name ($identifier)',
_("""Format of projects displayed by @projects."""))) _("""Format of projects displayed by @projects.""")))
conf.registerChannelValue(Redmine.format, 'issues', conf.registerChannelValue(Redmine.format, 'issues',
registry.String('\x02#%(id)i: %(subject)s\x02 (last update: ' registry.String('\x02#$id)i: $subject\x02 (last update: '
'%(updated_on)s / status: %(status__name)s)', '$updated_on / status: $status__name)',
_("""Format of issues displayed by @issues."""))) _("""Format of issues displayed by @issues.""")))
conf.registerChannelValue(Redmine.format, 'issue', conf.registerChannelValue(Redmine.format, 'issue',
registry.String('\x02#%(id)i (%(status__name)s)\x02: \x02%(subject)s\x02 ' registry.String('\x02#$id)i ($status__name)\x02: \x02$subject\x02 '
'in \x02%(project__name)s\x02 (%(project__id)i). Created by ' 'in \x02$project__name\x02 ($project__id)i). Created by '
'\x02%(author__name)s\x02 (%(author__id)i) on \x02%(created_on)s\x02, ' '\x02$author__name\x02 ($author__id)i) on \x02$created_on\x02, '
'last updated on \x02%(updated_on)s', 'last updated on \x02$updated_on',
_("""Format of issues displayed by @issue."""))) _("""Format of issues displayed by @issue.""")))
conf.registerGroup(Redmine.format, 'announces') conf.registerGroup(Redmine.format, 'announces')
conf.registerChannelValue(Redmine.format.announces, 'issue', conf.registerChannelValue(Redmine.format.announces, 'issue',
registry.String('Updated issue: \x02#%(id)i (%(status__name)s)\x02: ' registry.String('Updated issue: \x02#$id)i ($status__name)\x02: '
'\x02%(subject)s\x02 in \x02%(project__name)s\x02 (%(project__id)i).', '\x02$subject\x02 in \x02$project__name\x02 ($project__id)i).',
_("""Format of issues displayed by @issue."""))) _("""Format of issues displayed by @issue.""")))
conf.registerGroup(Redmine, 'announce') conf.registerGroup(Redmine, 'announce')

View File

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