From 7844cacd77733ef968e330d8856b2c6be003a637 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Wed, 22 May 2013 22:14:24 +0200 Subject: [PATCH] ERepublik & OEIS & Redmine: Fix possible denial of service via memory exhaustion (with %(thing)999999999999s for instance). --- ERepublik/plugin.py | 13 ++++++++----- OEIS/plugin.py | 7 +++++-- OEIS/test.py | 4 ++-- Redmine/config.py | 18 +++++++++--------- Redmine/plugin.py | 15 +++++++++------ 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/ERepublik/plugin.py b/ERepublik/plugin.py index 1459b82..30aa358 100644 --- a/ERepublik/plugin.py +++ b/ERepublik/plugin.py @@ -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.') diff --git a/OEIS/plugin.py b/OEIS/plugin.py index 9911256..6033aa8 100644 --- a/OEIS/plugin.py +++ b/OEIS/plugin.py @@ -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.') diff --git a/OEIS/test.py b/OEIS/test.py index 3521c24..bbd21a0 100644 --- a/OEIS/test.py +++ b/OEIS/test.py @@ -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: diff --git a/Redmine/config.py b/Redmine/config.py index bebb4fa..3247dc8 100644 --- a/Redmine/config.py +++ b/Redmine/config.py @@ -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') diff --git a/Redmine/plugin.py b/Redmine/plugin.py index 3c727f0..4ba7664 100644 --- a/Redmine/plugin.py +++ b/Redmine/plugin.py @@ -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 .""" - 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: