diff --git a/README.md b/README.md index ebcbd73..1b35a8c 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,12 @@ -
-
-
@@ -51,12 +40,18 @@ pip install -r requirements.txt
Before running it make sure these environment variables are set. You will need a [Sendgrid](https://sendgrid.com/docs/for-developers/sending-email/api-getting-started/) and [Discord](https://discordpy.readthedocs.io/en/latest/discord.html#discord-intro) account (both are free). Optionally consider making a [Mailgun](https://documentation.mailgun.com/en/latest/quickstart-sending.html#how-to-start-sending-email) account, since this bot uses Mailgun when Sendgrid fails to send an email:
+SMTP will be used first, if failed, Sendgrid, if failed again, Mailgun. Set SMTP_USE_STARTTLS to 'true' if using STARTTLS
```
export SENDGRID_API_KEY='YOUR_SENDGRID_API_KEY'
export SENDGRID_EMAIL='YOUR_SENDGRID_EMAIL'
export DISCORD_TOKEN='YOUR_DISCORD_TOKEN'
export MAILGUN_API_KEY='YOUR_MAILGUN_API_KEY'
export MAILGUN_DOMAIN='YOUR_MAILGUN_DOMAIN'
+export 'SMTP_USER'='YOUR_SMTP_EMAIL_ADDRESS'
+export 'SMTP_SERVER'='YOUR_SMTP_SERVER'
+export 'SMTP_PORT'='YOUR_SMTP_SERVER_PORT'
+export 'SMTP_PASSWORD'='YOUR_SMTP_PASSWORD'
+export 'SMTP_USE_STARTTLS'='true'
```
Run the bot with:
diff --git a/bot.py b/bot.py
index 2fac303..fbbd1dd 100644
--- a/bot.py
+++ b/bot.py
@@ -1,3 +1,4 @@
+import typing
import discord
from discord.ext import commands
import sqlite3
@@ -8,6 +9,9 @@
from sendgrid.helpers.mail import Mail
import requests
from keep_alive import keep_alive
+import fnmatch
+import smtplib
+from email.mime.text import MIMEText
conn = sqlite3.connect('bot.db')
c = conn.cursor()
@@ -59,6 +63,10 @@ def verify_user(userid, guildid):
c.execute("UPDATE users SET verified=1 WHERE userid=? AND guildid=?", (userid, guildid))
conn.commit()
+def unverify_user(userid, guildid):
+ c.execute("UPDATE users SET verified=0 WHERE userid=? AND guildid=?", (userid, guildid))
+ conn.commit()
+
def get_domains(guildid):
return get_guild(guildid)[1]
@@ -115,6 +123,29 @@ def mailgun_send(email_address, verification_code):
"subject": "Verify your server email",
"text": str(verification_code)})
+def domain_wildcard_match(domain_to_verify, domains_allowed):
+ for da in domains_allowed:
+ if fnmatch.fnmatch(domain_to_verify, da):
+ return True
+ return False
+
+def smtp_send(email_address, verification_code):
+ user_email = os.environ.get('SMTP_USER')
+ smtp_server = os.environ.get('SMTP_SERVER')
+ smtp_port = int(os.environ.get('SMTP_PORT'))
+ smtp_pswd = os.environ.get('SMTP_PASSWORD')
+ smtp_use_starttls = os.environ.get('SMTP_USE_STARTTLS') == 'true'
+ with smtplib.SMTP(smtp_server,smtp_port) as sv:
+ if smtp_use_starttls:
+ sv.starttls()
+ sv.login(user_email, smtp_pswd)
+ receiver = email_address
+ msg = MIMEText(f'Your verification code is {verification_code}. Please reply to EmailBot in the discord server')
+ msg['Subject'] = 'Verify your discord server email'
+ msg['From'] = user_email
+ msg['To'] = receiver
+ sv.sendmail(user_email, receiver, msg.as_string())
+
intents = discord.Intents.default()
intents.members = True
@@ -147,85 +178,115 @@ async def on_member_join(member):
role = discord.utils.get(member.guild.roles, name=check_on_join[3])
await member.add_roles(role)
-@client.event
-async def on_message(message):
- if message.author == client.user:
- return
- message_content = message.content.strip()
- if (message.guild == None) and email_check(message_content):
- users_guilds = get_users_guilds(message.author.id)
- if len(users_guilds) >= 1:
- guild_list = [i[1] for i in users_guilds if i[4] == 0]
- verif_list = []
- for i in guild_list:
- email_guild = get_emails_guilds(i, message_content)
- if len(email_guild) > 0:
- continue
- guild_domains = get_domains(i)
- if len(guild_domains) == 0:
- continue
- guild_domains = guild_domains.split('|')
- if message_content.split("@")[1] in guild_domains:
- verif_list.append(i)
- if len(verif_list) >= 1:
- random_code = random.randint(100000, 999999)
- for i in verif_list:
- insert_code(random_code, message.author.id, i)
- insert_email(message_content, message.author.id, i)
- emailmessage = Mail(
- from_email=os.environ.get('SENDGRID_EMAIL'),
- to_emails=message_content,
- subject='Verify your server email',
- html_content=str(random_code))
- try:
- sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
- response = sg.send(emailmessage)
- print(response.status_code)
- print(response.body)
- print(response.headers)
- await message.channel.send("Email sent. **Reply here with your verification code**. If you haven't received it, check your spam folder.")
- except Exception as e:
- mailgun_email = mailgun_send(message_content, random_code)
- if mailgun_email.status_code == 200:
- await message.channel.send("Email sent. **Reply here with your verification code**. If you haven't received it, check your spam folder.")
- else:
- await message.channel.send("Email failed to send.")
- else:
- await message.channel.send("Invalid email.")
+class MessageCog(commands.Cog):
+ def __init__(self, bot):
+ self.bot = bot
+ self._cd = commands.CooldownMapping.from_cooldown(1, 6.0, commands.BucketType.member) # Change accordingly
+ # rate, per, BucketType
+
+ def get_ratelimit(self, message: discord.Message) -> typing.Optional[int]:
+ """Returns the ratelimit left"""
+ bucket = self._cd.get_bucket(message)
+ return bucket.update_rate_limit()
+
+ @commands.Cog.listener()
+ async def on_message(self, message):
+ if message.guild:
+ return
+ if message.author == client.user:
+ return
+ # Getting the ratelimit left
+ ratelimit = self.get_ratelimit(message)
+ print(f'Rate limit: {ratelimit}')
+ if ratelimit is None:
+ # The user is not ratelimited, you can add the XP or level up the user here
+ pass
else:
- await message.channel.send("You have not joined a server.")
- elif (len(message_content) == 6) and message_content.isdigit():
- verif_code = int(message_content)
- prev_codes_f = get_users_codes(message.author.id, verif_code)
- prev_codes_g = [i for i in prev_codes_f if i[4] == 0]
- prev_codes = []
- for i in prev_codes_g:
- user_emails = get_emails_guilds(i[1], i[2])
- if len(user_emails) >= 1:
- continue
+ await message.channel.send("You are rate-limited. Please try again later.")
+ return
+
+ message_content = message.content.strip()
+ if (message.guild == None) and email_check(message_content):
+ users_guilds = get_users_guilds(message.author.id)
+ if len(users_guilds) >= 1:
+ guild_list = [i[1] for i in users_guilds if i[4] == 0]
+ verif_list = []
+ for i in guild_list:
+ email_guild = get_emails_guilds(i, message_content)
+ if len(email_guild) > 0:
+ continue
+ guild_domains = get_domains(i)
+ if len(guild_domains) == 0:
+ continue
+ guild_domains = guild_domains.split('|')
+ if domain_wildcard_match(message_content.split("@")[1],guild_domains):
+ verif_list.append(i)
+ if len(verif_list) >= 1:
+ random_code = random.randint(100000, 999999)
+ for i in verif_list:
+ insert_code(random_code, message.author.id, i)
+ insert_email(message_content, message.author.id, i)
+ emailmessage = Mail(
+ from_email=os.environ.get('SENDGRID_EMAIL'),
+ to_emails=message_content,
+ subject='Verify your server email',
+ html_content=str(random_code))
+ try :
+ smtp_send(message_content, random_code)
+ print('Email sent')
+ await message.channel.send("Email sent. **Reply here with your verification code**. If you haven't received it, check your spam folder.")
+ except Exception as e:
+ try:
+ sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
+ response = sg.send(emailmessage)
+ print(response.status_code)
+ print(response.body)
+ print(response.headers)
+ await message.channel.send("Email sent. **Reply here with your verification code**. If you haven't received it, check your spam folder.")
+ except Exception as ee:
+ mailgun_email = mailgun_send(message_content, random_code)
+ if mailgun_email.status_code == 200:
+ await message.channel.send("Email sent. **Reply here with your verification code**. If you haven't received it, check your spam folder.")
+ else:
+ await message.channel.send("Email failed to send.")
+ else:
+ await message.channel.send("Invalid email.")
else:
- prev_codes.append(i)
- if len(prev_codes) >= 1:
- for i in prev_codes:
- verify_user(message.author.id, i[1])
- curr_guild = client.get_guild(i[1])
- guild_db = get_guild(i[1])
- role = discord.utils.get(curr_guild.roles, name=guild_db[3])
- if role:
- member = curr_guild.get_member(message.author.id)
- if role not in member.roles:
- await member.add_roles(role)
+ await message.channel.send("You have not joined a server.")
+ elif (len(message_content) == 6) and message_content.isdigit():
+ verif_code = int(message_content)
+ prev_codes_f = get_users_codes(message.author.id, verif_code)
+ prev_codes_g = [i for i in prev_codes_f if i[4] == 0]
+ prev_codes = []
+ for i in prev_codes_g:
+ user_emails = get_emails_guilds(i[1], i[2])
+ if len(user_emails) >= 1:
+ continue
else:
- await curr_guild.create_role(name=guild_db[3])
+ prev_codes.append(i)
+ if len(prev_codes) >= 1:
+ for i in prev_codes:
+ verify_user(message.author.id, i[1])
+ curr_guild = client.get_guild(i[1])
+ guild_db = get_guild(i[1])
role = discord.utils.get(curr_guild.roles, name=guild_db[3])
- member = curr_guild.get_member(message.author.id)
- await member.add_roles(role)
- await message.channel.send("You have been verified on " + client.get_guild(i[1]).name + ".")
- else:
- await message.channel.send("Incorrect code.")
- elif message.guild == None:
- await message.channel.send("Invalid email.")
- await client.process_commands(message)
+ if role:
+ member = curr_guild.get_member(message.author.id)
+ if role not in member.roles:
+ await member.add_roles(role)
+ else:
+ await curr_guild.create_role(name=guild_db[3])
+ role = discord.utils.get(curr_guild.roles, name=guild_db[3])
+ member = curr_guild.get_member(message.author.id)
+ await member.add_roles(role)
+ await message.channel.send("You have been verified on " + client.get_guild(i[1]).name + ".")
+ else:
+ await message.channel.send("Incorrect code.")
+ elif message.guild == None:
+ await message.channel.send("Invalid email.")
+ # await client.process_commands(message)
+
+client.add_cog(MessageCog(client))
@client.event
async def on_guild_join(guild):
@@ -302,6 +363,7 @@ async def vstatus(ctx):
new_guild(ctx.guild.id)
check_on_join = get_guild(ctx.guild.id)
on_join = bool(check_on_join[2])
+ print('request vstatus')
await ctx.send("```" +
"Ping: " + "{0}ms".format(round(client.latency * 1000)) + "\n" +
"User commands: " + "\n" +
@@ -337,5 +399,22 @@ async def verify(ctx):
elif user_prev_verify[4] == 0:
await ctx.author.send(verify_msg(ctx.guild, check_on_join[1]))
+@client.command()
+async def unverify(ctx):
+ if ctx.guild:
+ check_on_join = get_guild(ctx.guild.id)
+ if check_on_join == None:
+ new_guild(ctx.guild.id)
+ unverify_user(ctx.author.id,ctx.guild.id)
+ insert_email("", ctx.author.id, ctx.guild.id)
+ curr_guild = client.get_guild(ctx.guild.id)
+ guild_db = get_guild(ctx.guild.id)
+ role = discord.utils.get(curr_guild.roles, name=guild_db[3])
+ member = curr_guild.get_member(ctx.author.id)
+ await member.remove_roles(role)
+ await ctx.author.send(f'You have been unverified on {curr_guild.name}.')
+
+
+
keep_alive()
client.run(os.environ.get('DISCORD_TOKEN'))
diff --git a/poetry.lock b/poetry.lock
index 9bcbdc7..790fd55 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -478,20 +478,39 @@ markupsafe = [
{file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
{file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"},
+ {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
{file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"},
+ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
{file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"},
+ {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"},
{file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"},
+ {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"},
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
]
mccabe = [