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 )
2020-04-20 22:05:32 +00:00
rules = [
" ** {} **. {} " . format ( i , cleandoc ( r ) )
for i , r in 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 "
2020-04-20 22:05:32 +00:00
rules [ rule_choice - 1 ] + = " \n " + config . hidden_term_line . format ( hash_choice_str )
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
2020-05-17 20:40:23 +00:00
self . hash_choice = random . choice ( tuple ( config . welcome_hashes ) )
2020-04-20 22:05:32 +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 :
2020-04-20 22:05:32 +00:00
await ctx . send (
f " This command is limited to "
f " <# { config . welcome_channel } >, unless forced. "
)
2019-04-24 07:47:07 +00:00
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 :
2020-04-20 22:05:32 +00:00
await ctx . send (
f " This command is limited to "
f " <# { config . welcome_channel } >, unless forced. "
)
2019-04-24 07:47:07 +00:00
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
2020-04-20 22:05:32 +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 ) :
2020-04-20 22:05:32 +00:00
snark = random . choice ( [ " bad human " , " no u " , " no u, rtfm " , " 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
2020-04-21 13:17:44 +00:00
success_role = guild . get_role ( config . named_roles [ " participant " ] )
2018-12-23 17:13:40 +00:00
# Get a list of stuff we'll allow and will consider close
allowed_names = [ f " @ { full_name } " , full_name , str ( member . id ) ]
2020-04-20 22:05:32 +00:00
close_names = [ f " @ { member . name } " , member . name , discrim , f " # { discrim } " ]
2018-12-23 17:13:40 +00:00
# Now add the same things but with newlines at the end of them
2020-04-20 22:05:32 +00:00
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 ]
2019-02-25 09:16:26 +00:00
# [ ͡° ͜ᔦ ͡°] 𝐖𝐞𝐥𝐜𝐨𝐦𝐞 𝐭 𝐨 𝐌 𝐚 𝐜 𝐎 𝐒 𝟗 .
2020-04-20 22:05:32 +00:00
allowed_names + = [ ( an + " \r " ) for an in allowed_names ]
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 :)
2020-04-20 22:05:32 +00:00
hash_allow = [
hashlib . new ( self . hash_choice , name . encode ( " utf-8 " ) ) . hexdigest ( )
for name in allowed_names
]
2018-12-23 17:13:40 +00:00
# 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 )
2020-04-20 22:05:32 +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
) ,
)
2019-04-24 07:24:59 +00:00
# Detect if the user uses the wrong hash algorithm
2020-05-17 20:40:23 +00:00
wrong_hash_algos = config . welcome_hashes - { self . hash_choice }
2019-04-24 07:24:59 +00:00
for algo in wrong_hash_algos :
for name in itertools . chain ( allowed_names , close_names ) :
2020-04-20 22:05:32 +00:00
if hashlib . new ( algo , name . encode ( " utf-8 " ) ) . hexdigest ( ) in mcl :
2019-04-24 08:59:04 +00:00
log_channel = self . bot . get_channel ( config . log_channel )
2020-04-20 22:05:32 +00:00
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
) :
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 :
2020-04-20 22:05:32 +00:00
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 ) )