Make bot less vulnerable

The bot still stores any number of explanations for a given word, and
prints all of them when using !wtf detail <word>. This means that it is
still vulnerable to some types of attacks.

Maybe I'll fix that sometime in the future.
This commit is contained in:
Joscha 2019-05-15 06:25:54 +00:00
parent f80a8e0b7c
commit 7d7c5a0c5f
2 changed files with 57 additions and 18 deletions

65
wtf.py
View file

@ -12,6 +12,11 @@ else:
logger = logging.getLogger(__name__)
class Wtf(yaboli.Module):
MAX_TERMS = 5
MAX_TERM_LENGTH = 1024
MAX_EXPLANATIONS = 15
MAX_EXPLANATION_LENGTH = 1024
DESCRIPTION = ("a database of explanations for words, acronyms and"
" initialisms")
HELP_GENERAL = DESCRIPTION
@ -53,49 +58,75 @@ class Wtf(yaboli.Module):
self.register_general("wtf", self.cmd_wtf)
@staticmethod
def _format_explanations(explanations, detail=False):
def _format_explanations(self, explanations, detail=False):
# Id, Term, Explanation, Author
if detail:
return [f"{i}: {t}{e} (by {a})" for i, t, e, a in explanations]
explanations = [f"{i}: {t}{e} (by {a})" for i, t, e, a in explanations]
else:
return [f"{t}{e}" for _, t, e, _ in explanations]
explanations = [f"{t}{e}" for _, t, e, _ in explanations]
if len(explanations) > self.MAX_EXPLANATIONS:
message = ("Some explanations were omitted because this bot only"
f" displays {self.MAX_EXPLANATIONS} explanations per"
" term.")
explanations = explanations[:-1] + [message]
return explanations
async def _find_explanations(self, terms, detail=False):
lines = []
for term in terms:
explanations = await self.db.find_full(term)
explanations = await self.db.find_full(term, self.MAX_EXPLANATIONS + 1)
if explanations:
lines.extend(self._format_explanations(explanations, detail=detail))
else:
lines.append(f"{term!r} not found.")
return lines
async def send_explanations(self, message, termstr):
terms = [term for term in termstr.split() if term]
terms = terms[:self.MAX_TERMS]
if not terms: return
if max(map(len, terms)) > self.MAX_TERM_LENGTH:
await message.reply(("A term can be at most"
f" {self.MAX_TERM_LENGTH} characters long."))
return
lines = await self._find_explanations(terms)
await message.reply("\n".join(lines))
return
async def on_send(self, room, message):
await super().on_send(room, message)
match = self.RE_WTF_IS.fullmatch(message.content)
if match:
terms = match.group(1)
terms = [term for term in terms.split() if term]
if not terms: return
lines = await self._find_explanations(terms)
await message.reply("\n".join(lines))
await self.send_explanations(message, terms)
async def cmd_wtf(self, room, message, args):
match_is = self.RE_IS.fullmatch(args.raw)
if match_is:
terms = match_is.group(1)
terms = [term for term in terms.split() if term]
if not terms: return
lines = await self._find_explanations(terms)
await message.reply("\n".join(lines))
return
await self.send_explanations(message, terms)
match_add = self.RE_ADD.fullmatch(args.raw)
if match_add:
term = match_add.group(1)
explanation = match_add.group(2).strip()
if len(term) > self.MAX_TERM_LENGTH:
await message.reply(("A term can be at most"
f" {self.MAX_TERM_LENGTH} characters long."))
return
if len(explanation) > self.MAX_EXPLANATION_LENGTH:
await message.reply(("An explanation can be at most"
f" {self.MAX_EXPLANATION_LENGTH} characters long."))
return
await self.db.add(term, explanation, message.sender.nick)
logger.info((f"{message.sender.atmention} added explanation:"
f" {term} - {explanation}"))
@ -124,6 +155,12 @@ class Wtf(yaboli.Module):
if match_replace:
aid = match_replace.group(1)
explanation = match_replace.group(2).strip()
if len(explanation) > self.MAX_EXPLANATION_LENGTH:
await message.reply(("An explanation can be at most"
f" {self.MAX_EXPLANATION_LENGTH} characters long."))
return
term = await self.db.get(aid)
if term is None:
await message.reply(f"No explanation with id {aid} exists.")

View file

@ -31,21 +31,23 @@ class WtfDB(yaboli.Database):
""", (acronym, explanation, author))
@yaboli.operation
def find(self, db, acronym):
def find(self, db, acronym, limit):
c = db.execute("""
SELECT acronym, explanation FROM acronyms
WHERE NOT deleted AND p_lower(acronym) = ?
ORDER BY acronym_id ASC
""", (acronym.lower(),))
LIMIT ?
""", (acronym.lower(), limit))
return c.fetchall()
@yaboli.operation
def find_full(self, db, acronym):
def find_full(self, db, acronym, limit):
c = db.execute("""
SELECT acronym_id, acronym, explanation, author FROM acronyms
WHERE NOT deleted AND p_lower(acronym) = ?
ORDER BY acronym_id ASC
""", (acronym.lower(),))
LIMIT ?
""", (acronym.lower(), limit))
return c.fetchall()
@yaboli.operation