import discord from discord.ext import commands from discord.ext.commands import Cog import asyncio import config import random from inspect import cleandoc import hashlib import itertools from helpers.checks import check_if_staff class Verification(Cog): def __init__(self, bot): self.bot = bot self.hash_choice = random.choice(config.welcome_hashes) # Export reset channel functions self.bot.do_reset = self.do_reset self.bot.do_resetalgo = self.do_resetalgo async def do_reset(self, channel, author, limit: int = 100): await channel.purge(limit=limit) await channel.send(config.welcome_header) rules = ['**{}**. {}'.format(i, cleandoc(r)) for i, r in enumerate(config.welcome_rules, 1)] rule_choice = random.randint(2, len(rules)) hash_choice_str = self.hash_choice.upper() if hash_choice_str == "BLAKE2B": hash_choice_str += "-512" elif hash_choice_str == "BLAKE2S": hash_choice_str += "-256" rules[rule_choice - 1] += \ '\n' + config.hidden_term_line.format(hash_choice_str) msg = f"๐Ÿ—‘ **Reset**: {author} cleared {limit} messages "\ f" in {channel.mention}" msg += f"\n๐Ÿ’ฌ __Current challenge location__: under rule {rule_choice}" log_channel = self.bot.get_channel(config.log_channel) await log_channel.send(msg) # find rule that puts us over 2,000 characters, if any total = 0 messages = [] current_message = "" for item in rules: total += len(item) + 2 # \n\n if total < 2000: current_message += item + "\n\n" else: # we've hit the limit; split! messages += [current_message] current_message = "\n\u200B\n" + item + "\n\u200B\n" total = 0 messages += [current_message] for item in messages: await channel.send(item) await asyncio.sleep(1) for x in config.welcome_footer: await channel.send(cleandoc(x)) await asyncio.sleep(1) async def do_resetalgo(self, channel, author, limit: int = 100): # randomize hash_choice on reset self.hash_choice = \ random.choice(tuple(hashlib.algorithms_guaranteed - self.blacklisted_hashes - {self.hash_choice})) msg = f"๐Ÿ“˜ **Reset Algorithm**: {author} reset "\ f"algorithm in {channel.mention}" msg += f"\n๐Ÿ’ฌ __Current algorithm__: {self.hash_choice.upper()}" log_channel = self.bot.get_channel(config.log_channel) await log_channel.send(msg) await self.do_reset(channel, author) @commands.check(check_if_staff) @commands.command() async def reset(self, ctx, limit: int = 100, force: bool = False): """Wipes messages and pastes the welcome message again. Staff only.""" if ctx.message.channel.id != config.welcome_channel and not force: await ctx.send(f"This command is limited to" f" <#{config.welcome_channel}>, unless forced.") return await self.do_reset(ctx.channel, ctx.author.mention, limit) @commands.check(check_if_staff) @commands.command() async def resetalgo(self, ctx, limit: int = 100, force: bool = False): """Resets the verification algorithm and does what reset does. Staff only.""" if ctx.message.channel.id != config.welcome_channel and not force: await ctx.send(f"This command is limited to" f" <#{config.welcome_channel}>, unless forced.") return await self.do_resetalgo(ctx.channel, ctx.author.mention, limit) async def process_message(self, message): """Big code that makes me want to shoot myself Not really a rewrite but more of a port Git blame tells me that I should blame/credit Robin Lambertz""" if message.channel.id == config.welcome_channel: # Assign common stuff into variables to make stuff less of a mess member = message.author full_name = str(member) discrim = str(member.discriminator) guild = message.guild chan = message.channel mcl = message.content.lower() # Reply to users that insult the bot oof = ["bad", "broken", "buggy", "bugged", "stupid", "dumb", "silly", "fuck", "heck", "h*ck"] if "bot" in mcl and any(insult in mcl for insult in oof): snark = random.choice(["bad human", "no u", "no u, rtfm", "pebkac"]) return await chan.send(snark) # Get the role we will give in case of success success_role = guild.get_role(config.participant_role) # Get a list of stuff we'll allow and will consider close allowed_names = [f"@{full_name}", full_name, str(member.id)] close_names = [f"@{member.name}", member.name, discrim, f"#{discrim}"] # Now add the same things but with newlines at the end of them allowed_names += [(an + '\n') for an in allowed_names] close_names += [(cn + '\n') for cn in close_names] allowed_names += [(an + '\r\n') for an in allowed_names] close_names += [(cn + '\r\n') for cn in close_names] # [ อกยฐ อœแ”ฆ อกยฐ] ๐–๐ž๐ฅ๐œ๐จ๐ฆ๐ž ๐ญ๐จ ๐Œ๐š๐œ ๐Ž๐’ ๐Ÿ—. allowed_names += [(an + '\r') for an in allowed_names] close_names += [(cn + '\r') for cn in close_names] # Finally, hash the stuff so that we can access them later :) hash_allow = [hashlib.new(self.hash_choice, name.encode('utf-8')).hexdigest() for name in allowed_names] # I'm not even going to attempt to break those into lines jfc if any(allow in mcl for allow in hash_allow): await member.add_roles(success_role) return await chan.purge(limit=100, check=lambda m: m.author == message.author or (m.author == self.bot.user and message.author.mention in m.content)) # Detect if the user uses the wrong hash algorithm wrong_hash_algos = hashlib.algorithms_guaranteed - \ {self.hash_choice} - self.blacklisted_hashes for algo in wrong_hash_algos: for name in itertools.chain(allowed_names, close_names): if hashlib.new(algo, name.encode('utf-8')).hexdigest() in mcl: log_channel = self.bot.get_channel(config.log_channel) await log_channel.send(f"User {message.author.mention} tried verification with algo {algo} instead of {self.hash_choice}.") return await chan.send(f"{message.author.mention} :no_entry: Close, but not quite. Go back and re-read!") if full_name in message.content or str(member.id) in message.content or member.name in message.content or discrim in message.content: no_text = ":no_entry: Incorrect. You need to do something *specific* with your name and discriminator instead of just posting it. Please re-read the rules carefully and look up any terms you are not familiar with." rand_num = random.randint(1, 100) if rand_num == 42: no_text = "you're doing it wrong" elif rand_num == 43: no_text = "ugh, wrong, read the rules." elif rand_num == 44: no_text = "\"The definition of insanity is doing the same thing over and over again, but expecting different results.\"\n-Albert Einstein" await chan.send(f"{message.author.mention} {no_text}") @Cog.listener() async def on_message(self, message): if message.author.bot: return try: await self.process_message(message) except discord.errors.Forbidden: chan = self.bot.get_channel(message.channel) await chan.send("๐Ÿ’ข I don't have permission to do this.") @Cog.listener() async def on_message_edit(self, before, after): if after.author.bot: return try: await self.process_message(after) except discord.errors.Forbidden: chan = self.bot.get_channel(after.channel) await chan.send("๐Ÿ’ข I don't have permission to do this.") def setup(bot): bot.add_cog(Verification(bot))