2018-12-23 16:31:12 +00:00
import discord
from discord . ext import commands
2019-02-28 22:10:30 +00:00
from discord . ext . commands import Cog
2018-12-23 16:31:12 +00:00
import asyncio
import config
import random
from inspect import cleandoc
2018-12-23 17:13:40 +00:00
import hashlib
2019-04-24 05:00:33 +00:00
import itertools
2018-12-26 11:36:55 +00:00
from helpers . checks import check_if_staff
2018-12-23 16:31:12 +00:00
2019-02-28 22:10:30 +00:00
class Verification ( Cog ) :
2019-04-24 03:58:17 +00:00
def __init__ ( self , bot ) :
2018-12-23 16:31:12 +00:00
self . bot = bot
2020-04-20 21:56:34 +00:00
self . hash_choice = random . choice ( config . welcome_hashes )
2018-12-23 16:31:12 +00:00
2019-04-24 07:47:07 +00:00
# Export reset channel functions
self . bot . do_reset = self . do_reset
self . bot . do_resetalgo = self . do_resetalgo
2018-12-23 16:31:12 +00:00
2019-04-24 07:47:07 +00:00
async def do_reset ( self , channel , author , limit : int = 100 ) :
await channel . purge ( limit = limit )
2019-04-24 05:24:26 +00:00
2020-04-20 21:56:34 +00:00
await channel . send ( config . welcome_header )
2018-12-23 16:31:12 +00:00
rules = [ ' ** {} **. {} ' . format ( i , cleandoc ( r ) ) for i , r in
2020-04-20 21:56:34 +00:00
enumerate ( config . welcome_rules , 1 ) ]
2019-02-08 18:55:39 +00:00
rule_choice = random . randint ( 2 , len ( rules ) )
2019-06-29 18:29:19 +00:00
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 "
2019-04-24 07:24:59 +00:00
rules [ rule_choice - 1 ] + = \
2020-04-20 21:56:34 +00:00
' \n ' + config . hidden_term_line . format ( hash_choice_str )
2019-04-24 07:47:07 +00:00
msg = f " 🗑 **Reset**: { author } cleared { limit } messages " \
f " in { channel . mention } "
2018-12-23 16:31:12 +00:00
msg + = f " \n 💬 __Current challenge location__: under rule { rule_choice } "
2019-02-16 13:55:26 +00:00
log_channel = self . bot . get_channel ( config . log_channel )
2018-12-24 00:18:40 +00:00
await log_channel . send ( msg )
2019-04-24 07:24:59 +00:00
2018-12-23 16:31:12 +00:00
# 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 :
2019-04-24 07:47:07 +00:00
await channel . send ( item )
2018-12-23 16:31:12 +00:00
await asyncio . sleep ( 1 )
2020-04-20 21:56:34 +00:00
for x in config . welcome_footer :
2019-04-24 07:47:07 +00:00
await channel . send ( cleandoc ( x ) )
2019-01-22 21:11:32 +00:00
await asyncio . sleep ( 1 )
2018-12-23 16:31:12 +00:00
2019-04-24 07:47:07 +00:00
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 } ) )
2019-04-24 07:49:45 +00:00
msg = f " 📘 **Reset Algorithm**: { author } reset " \
f " algorithm in { channel . mention } "
2019-04-24 07:47:07 +00:00
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
2019-04-25 07:14:12 +00:00
await self . do_resetalgo ( ctx . channel , ctx . author . mention , limit )
2019-04-24 07:47:07 +00:00
2018-12-23 17:13:40 +00:00
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 ( )
2019-02-25 09:28:37 +00:00
# Reply to users that insult the bot
2019-02-25 10:09:18 +00:00
oof = [ " bad " , " broken " , " buggy " , " bugged " ,
" stupid " , " dumb " , " silly " , " fuck " , " heck " , " h*ck " ]
2019-02-25 09:28:37 +00:00
if " bot " in mcl and any ( insult in mcl for insult in oof ) :
2019-02-25 09:21:31 +00:00
snark = random . choice ( [ " bad human " ,
" no u " ,
2019-02-25 09:28:37 +00:00
" no u, rtfm " ,
2019-02-25 09:21:31 +00:00
" pebkac " ] )
2019-02-25 09:17:35 +00:00
return await chan . send ( snark )
2019-02-25 09:16:26 +00:00
2018-12-23 17:13:40 +00:00
# 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 ]
2019-02-21 07:22:11 +00:00
allowed_names + = [ ( an + ' \r \n ' ) for an in allowed_names ]
close_names + = [ ( cn + ' \r \n ' ) for cn in close_names ]
2019-02-25 09:16:26 +00:00
# [ ͡° ͜ᔦ ͡°] 𝐖𝐞𝐥𝐜𝐨𝐦𝐞 𝐭 𝐨 𝐌 𝐚 𝐜 𝐎 𝐒 𝟗 .
allowed_names + = [ ( an + ' \r ' ) for an in allowed_names ]
2019-02-21 07:22:11 +00:00
close_names + = [ ( cn + ' \r ' ) for cn in close_names ]
2018-12-23 17:13:40 +00:00
# Finally, hash the stuff so that we can access them later :)
2019-04-24 07:24:59 +00:00
hash_allow = [ hashlib . new ( self . hash_choice ,
name . encode ( ' utf-8 ' ) ) . hexdigest ( )
2018-12-23 17:13:40 +00:00
for name in allowed_names ]
# I'm not even going to attempt to break those into lines jfc
2019-04-24 01:32:30 +00:00
if any ( allow in mcl for allow in hash_allow ) :
2018-12-23 17:13:40 +00:00
await member . add_roles ( success_role )
2019-04-24 07:24:59 +00:00
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 ) :
2019-04-24 08:59:04 +00:00
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 } . " )
2019-04-24 07:24:59 +00:00
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 :
2019-02-26 11:49:18 +00:00
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. "
2019-04-23 16:12:44 +00:00
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 "
2019-02-26 11:49:18 +00:00
await chan . send ( f " { message . author . mention } { no_text } " )
2019-04-24 01:32:30 +00:00
2019-02-28 22:10:30 +00:00
@Cog.listener ( )
2018-12-23 17:13:40 +00:00
async def on_message ( self , message ) :
2019-01-27 23:04:24 +00:00
if message . author . bot :
return
2018-12-23 17:13:40 +00:00
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. " )
2019-02-28 22:10:30 +00:00
@Cog.listener ( )
2018-12-23 17:13:40 +00:00
async def on_message_edit ( self , before , after ) :
2019-02-25 09:16:26 +00:00
if after . author . bot :
2019-01-27 23:04:24 +00:00
return
2018-12-23 17:13:40 +00:00
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. " )
2018-12-23 16:31:12 +00:00
def setup ( bot ) :
bot . add_cog ( Verification ( bot ) )