From e4b153bf3b4f924081f4f64674479eb8dc5a8a5b Mon Sep 17 00:00:00 2001 From: sandlerino Date: Fri, 18 Oct 2024 13:41:40 +0200 Subject: [PATCH 1/8] minor purge update --- purge/module.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/purge/module.py b/purge/module.py index 8529aae..c22ced5 100644 --- a/purge/module.py +++ b/purge/module.py @@ -35,7 +35,7 @@ async def purge(self, ctx: commands.Context, count: Optional[int] = None): await ctx.reply( _( ctx, - "Please use either a reply or provide a number of messages to delete. Not both.", + "Please use either a reply or provide a positive number of messages to delete. Not both.", ) ) return @@ -69,7 +69,7 @@ async def purge(self, ctx: commands.Context, count: Optional[int] = None): await ctx.send(_(ctx, "Aborted.")) return - elif count is not None: + elif count is not None and count > 0: if count > 10: embed = utils.discord.create_embed( author=ctx.author, @@ -107,7 +107,7 @@ async def purge(self, ctx: commands.Context, count: Optional[int] = None): await ctx.reply( _( ctx, - "Please use either a reply or provide a number of messages to delete.", + "Please use either a reply or provide a positive number of messages to delete.", ) ) return @@ -117,8 +117,10 @@ async def purge(self, ctx: commands.Context, count: Optional[int] = None): ctx.channel, f"Deleted {len(deleted)} message(s)", ) + await ctx.message.delete() await channel.send( - _(ctx, "Deleted {deleted} message(s)").format(deleted=len(deleted)) + _(ctx, "Deleted {deleted} message(s)").format(deleted=len(deleted)), + delete_after=10, ) From fa24db7c1109f9fec0f47efff4450663bc426d17 Mon Sep 17 00:00:00 2001 From: sandlerino Date: Fri, 18 Oct 2024 13:43:57 +0200 Subject: [PATCH 2/8] updated command description --- purge/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purge/module.py b/purge/module.py index c22ced5..cfc713d 100644 --- a/purge/module.py +++ b/purge/module.py @@ -24,7 +24,7 @@ def _not_pinned(message: discord.Message) -> bool: async def purge(self, ctx: commands.Context, count: Optional[int] = None): """Purge spam messages. - Either reply to the oldest message you want to keep or provide a number of messages to delete. + Either reply to the oldest message you want to keep or provide a positive number of messages to delete. This command keeps pinned messages intact. """ From ec89b96e411a435607ad63129c18025fee358548 Mon Sep 17 00:00:00 2001 From: sandlerino Date: Fri, 18 Oct 2024 13:55:42 +0200 Subject: [PATCH 3/8] popie fix --- po/cs.popie | 8 ++++---- po/sk.popie | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/po/cs.popie b/po/cs.popie index c2494c6..7bf4604 100644 --- a/po/cs.popie +++ b/po/cs.popie @@ -19,8 +19,8 @@ msgstr Komentář odebrán. msgid Unknown author msgstr Neznámý autor. -msgid Please use either a reply or provide a number of messages to delete. Not both. -msgstr Prosím použij odpověď na zprávu, nebo počet zpráv ke smazání. Ne obojí. +msgid Please use either a reply or provide a positive number of messages to delete. Not both. +msgstr Prosím použij odpověď na zprávu, nebo kladný počet zpráv ke smazání. Ne obojí. msgid Confirm delete. msgstr Potvrzení smazání. @@ -37,8 +37,8 @@ msgstr Akce zrušena. msgid Number of messages to delete msgstr Počet zpráv ke smazání -msgid Please use either a reply or provide a number of messages to delete. -msgstr Prosím použij odpověď na zprávu, nebo počet zpráv ke smazání. +msgid Please use either a reply or provide a positive number of messages to delete. +msgstr Prosím použij odpověď na zprávu, nebo kladný počet zpráv ke smazání. msgid Deleted {deleted} message(s) msgstr Smazáno {deleted} zpráv. diff --git a/po/sk.popie b/po/sk.popie index 48d75a6..8920fae 100644 --- a/po/sk.popie +++ b/po/sk.popie @@ -19,8 +19,8 @@ msgstr Komentár odobraný. msgid Unknown author msgstr Neznámy autor. -msgid Please use either a reply or provide a number of messages to delete. Not both. -msgstr Prosím použi odpoveď na správu, alebo počet správ na zmazanie. Nie oboje. +msgid Please use either a reply or provide a positive number of messages to delete. Not both. +msgstr msgid Confirm delete. msgstr Potvrdenie zmazania @@ -37,8 +37,8 @@ msgstr Akcia zrušená. msgid Number of messages to delete msgstr Počet správ na vymazanie. -msgid Please use either a reply or provide a number of messages to delete. -msgstr Prosím použi odpoveď na správu, alebo počet správ na zmazanie. +msgid Please use either a reply or provide a positive number of messages to delete. +msgstr msgid Deleted {deleted} message(s) msgstr Zmazané {deleted} správ. From 79ef64aa5f88a0ccfb56f49906b5d1d1872801f3 Mon Sep 17 00:00:00 2001 From: sandlerino Date: Fri, 18 Oct 2024 14:00:02 +0200 Subject: [PATCH 4/8] forgot about sk.popie --- po/sk.popie | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/sk.popie b/po/sk.popie index 8920fae..3a11394 100644 --- a/po/sk.popie +++ b/po/sk.popie @@ -20,7 +20,7 @@ msgid Unknown author msgstr Neznámy autor. msgid Please use either a reply or provide a positive number of messages to delete. Not both. -msgstr +msgstr Prosím použi odpoveď na správu, alebo kladný počet správ na zmazanie. Nie oboje. msgid Confirm delete. msgstr Potvrdenie zmazania @@ -38,7 +38,7 @@ msgid Number of messages to delete msgstr Počet správ na vymazanie. msgid Please use either a reply or provide a positive number of messages to delete. -msgstr +msgstr Prosím použi odpoveď na správu, alebo kladný počet správ na zmazanie. Nie oboje. msgid Deleted {deleted} message(s) msgstr Zmazané {deleted} správ. From 763ef7503e7a9b5f5175ab6114f141675dd48e5f Mon Sep 17 00:00:00 2001 From: sandlerino Date: Sat, 19 Oct 2024 13:18:24 +0200 Subject: [PATCH 5/8] fix sk.popie --- po/sk.popie | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sk.popie b/po/sk.popie index 3a11394..777ad1e 100644 --- a/po/sk.popie +++ b/po/sk.popie @@ -38,8 +38,7 @@ msgid Number of messages to delete msgstr Počet správ na vymazanie. msgid Please use either a reply or provide a positive number of messages to delete. -msgstr Prosím použi odpoveď na správu, alebo kladný počet správ na zmazanie. Nie oboje. - +msgstr Prosím použi odpoveď na správu, alebo kladný počet správ na zmazanie. msgid Deleted {deleted} message(s) msgstr Zmazané {deleted} správ. From dc7de73199ee6178b37c1911f9d3c5162f5c56fb Mon Sep 17 00:00:00 2001 From: sandlerino Date: Sat, 19 Oct 2024 13:18:51 +0200 Subject: [PATCH 6/8] fix sk.popie --- po/sk.popie | 1 + 1 file changed, 1 insertion(+) diff --git a/po/sk.popie b/po/sk.popie index 777ad1e..8d8b2ff 100644 --- a/po/sk.popie +++ b/po/sk.popie @@ -39,6 +39,7 @@ msgstr Počet správ na vymazanie. msgid Please use either a reply or provide a positive number of messages to delete. msgstr Prosím použi odpoveď na správu, alebo kladný počet správ na zmazanie. + msgid Deleted {deleted} message(s) msgstr Zmazané {deleted} správ. From ea0a53dd8244a5f3b57c455c9c2ac26bc8cb0a70 Mon Sep 17 00:00:00 2001 From: sandlerino Date: Fri, 18 Apr 2025 19:25:13 +0200 Subject: [PATCH 7/8] emergency fix, verify overhaul --- verify/module.py | 126 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 32 deletions(-) diff --git a/verify/module.py b/verify/module.py index c4fff3f..70e5279 100644 --- a/verify/module.py +++ b/verify/module.py @@ -1,20 +1,25 @@ import asyncio +import base64 import contextlib import datetime +import email import json import os import random import re import smtplib +import ssl import string import tempfile +import urllib + import unidecode from typing import Dict, List, Union, Optional from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart -import imap_tools +import imaplib import discord from discord.ext import commands @@ -35,7 +40,10 @@ SMTP_SERVER: str = os.getenv("SMTP_SERVER") IMAP_SERVER: str = os.getenv("IMAP_SERVER") SMTP_ADDRESS: str = os.getenv("SMTP_ADDRESS") -SMTP_PASSWORD: str = os.getenv("SMTP_PASSWORD") + +CLIENT_ID: str = os.getenv("CLIENT_ID") +CLIENT_SECRET: str = os.getenv("CLIENT_SECRET") +CLIENT_REFRESH_TOKEN: str = os.getenv("CLIENT_REFRESH_TOKEN") def test_dotenv() -> None: @@ -43,10 +51,14 @@ def test_dotenv() -> None: raise exceptions.DotEnvException("SMTP_SERVER is not set.") if type(SMTP_ADDRESS) != str: raise exceptions.DotEnvException("SMTP_ADDRESS is not set.") - if type(SMTP_PASSWORD) != str: - raise exceptions.DotEnvException("SMTP_PASSWORD is not set.") + if type(CLIENT_ID) != str: + raise exceptions.DotEnvException("CLIENT_ID is not set.") if type(IMAP_SERVER) != str: raise exceptions.DotEnvException("IMAP_SERVER is not set.") + if type(CLIENT_SECRET) != str: + raise exceptions.DotEnvException("CLIENT_SECRET is not set.") + if type(CLIENT_REFRESH_TOKEN) != str: + raise exceptions.DotEnvException("CLIENT_REFRESH_TOKEN is not set.") test_dotenv() @@ -1036,8 +1048,10 @@ async def _send_email( """Send the verification e-mail.""" try: with smtplib.SMTP_SSL(SMTP_SERVER) as server: + _auth_string = self._refresh_token(CLIENT_ID, CLIENT_SECRET, CLIENT_REFRESH_TOKEN)["access_token"] + _auth_string = self._generate_oauth_2_string(SMTP_ADDRESS, _auth_string, base64_encode=False) server.ehlo() - server.login(SMTP_ADDRESS, SMTP_PASSWORD) + server.docmd('AUTH', 'XOAUTH2 ' + base64.b64encode(_auth_string.encode('utf-8')).decode('utf-8')) server.send_message(message) return True except smtplib.SMTPException as exc: @@ -1107,51 +1121,99 @@ def _check_inbox_for_errors(self): """ unread_messages = [] - with imap_tools.MailBox(IMAP_SERVER).login( - SMTP_ADDRESS, SMTP_PASSWORD - ) as mailbox: - messages = [ - m - for m in mailbox.fetch( - imap_tools.AND(seen=False), - mark_seen=False, - ) - ] - mark_as_read: List = [] + with imaplib.IMAP4_SSL(IMAP_SERVER, ssl_context=ssl.create_default_context()) as mailbox: + _auth_string = self._refresh_token(CLIENT_ID, CLIENT_SECRET, CLIENT_REFRESH_TOKEN)["access_token"] + _auth_string = self._generate_oauth_2_string(SMTP_ADDRESS, _auth_string, base64_encode=False) + mailbox.authenticate('XOAUTH2', lambda x: _auth_string) + mailbox.select("INBOX", readonly=False) + status, data = mailbox.search(None, 'UNSEEN') + message_ids = data[0].split() + print("haloooooooo") + for msg_id in message_ids: + status, msg_data = mailbox.fetch(msg_id, '(RFC822)') + if status != 'OK': + continue - for m in messages: - has_delivery_status: bool = False + msg = email.message_from_bytes(msg_data[0][1]) + has_delivery_status = False - for part in m.obj.walk(): - if part.get_content_type() == "message/delivery-status": + # Procházení částí zprávy + if msg.is_multipart(): + for part in msg.walk(): + if part.get_content_type() == 'message/delivery-status': + has_delivery_status = True + break + else: + # Pokud zpráva není multipart, kontrolujeme přímo + if msg.get_content_type() == 'message/delivery-status': has_delivery_status = True - break if not has_delivery_status: continue - rfc_message = m.obj.as_string() + # Převedení celé zprávy na string kvůli hledání hlaviček + rfc_message = msg.as_string() info: dict = {} - for line in rfc_message.split("\n"): + for line in rfc_message.split('\n'): if line.startswith(MAIL_HEADER_PREFIX): - key, value = line.split(":", 1) - info[key.replace(MAIL_HEADER_PREFIX, "")] = value.strip() + if ':' in line: + key, value = line.split(':', 1) + info[key.replace(MAIL_HEADER_PREFIX, '')] = value.strip() + if not info: continue - mark_as_read.append(m) - info["subject"] = m.subject + # Přidání předmětu a uložení do výsledného listu + info['subject'] = msg['Subject'] unread_messages.append(info) - mailbox.flag( - [m.uid for m in mark_as_read], - (imap_tools.MailMessageFlags.SEEN,), - True, - ) + # Odhlášení + mailbox.logout() return unread_messages + def _generate_oauth_2_string(self, username, access_token, base64_encode=True): + """Generates an IMAP OAuth2 authentication string. + + See https://developers.google.com/google-apps/gmail/oauth2_overview + + Args: + username: the username (email address) of the account to authenticate + access_token: An OAuth2 access token. + base64_encode: Whether to base64-encode the output. + + Returns: + The SASL argument for the OAuth2 mechanism. + """ + auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token) + if base64_encode: + auth_string = base64.b64encode(auth_string.encode('utf-8')) + return auth_string + + def _refresh_token(self, client_id, client_secret, refresh_token): + """Obtains a new token given a refresh token. + + See https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh + + Args: + client_id: Client ID obtained by registering your app. + client_secret: Client secret obtained by registering your app. + refresh_token: A previously-obtained refresh token. + Returns: + The decoded response from the Google Accounts server, as a dict. Expected + fields include 'access_token', 'expires_in', and 'refresh_token'. + """ + params = {} + params['client_id'] = client_id + params['client_secret'] = client_secret + params['refresh_token'] = refresh_token + params['grant_type'] = 'refresh_token' + request_url = "https://accounts.google.com/o/oauth2/token" + + response = urllib.request.urlopen(request_url, urllib.parse.urlencode(params).encode('utf-8')).read() + return json.loads(response) + async def setup(bot) -> None: await bot.add_cog(Verify(bot)) From 8ded421cfd054a442053f8bdd3e7a9098b729459 Mon Sep 17 00:00:00 2001 From: sandlerino Date: Fri, 18 Apr 2025 19:31:09 +0200 Subject: [PATCH 8/8] added credits --- verify/module.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/verify/module.py b/verify/module.py index 70e5279..b35aad1 100644 --- a/verify/module.py +++ b/verify/module.py @@ -1176,6 +1176,8 @@ def _check_inbox_for_errors(self): def _generate_oauth_2_string(self, username, access_token, base64_encode=True): """Generates an IMAP OAuth2 authentication string. + CODE FROM: https://github.com/google/gmail-oauth2-tools/tree/master + See https://developers.google.com/google-apps/gmail/oauth2_overview Args: @@ -1194,6 +1196,8 @@ def _generate_oauth_2_string(self, username, access_token, base64_encode=True): def _refresh_token(self, client_id, client_secret, refresh_token): """Obtains a new token given a refresh token. + CODE FROM: https://github.com/google/gmail-oauth2-tools/tree/master + See https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh Args: