Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create OTP class based on SMTP SSL #10

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion module/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
REPORT,
HELP,
HELP_CMD_TEXT,
START_CMD_TEXT
START_CMD_TEXT,
MAIL_TEMPLATE
)
8 changes: 8 additions & 0 deletions module/data/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@

REPORT = "Segnalazioni Rappresentanti 📬"
HELP = "Help ❔"

MAIL_TEMPLATE = (
"Ciao!\n\n"
"Se stai ricevendo questo messaggio vuol dire che ti stai registrando a FinderUniCT-Bot. "
"Se non sei stato tu, ignora semplicemente questo messaggio.\n"
"Il tuo codice OTP e': {otp}\n\n"
"Il team di FinderUniCT-Bot!"
)
95 changes: 95 additions & 0 deletions module/otp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
OTP module.
"""
import os
import random
import smtplib
from email.mime.text import MIMEText

from module.data import MAIL_TEMPLATE

#: Define the following in settings.yaml
HOST = 'HOST'
USER = "USER"
PASSWORD = "PASSWORD"

class OTPException(Exception):
pass

class OTPConnectionFailed(OTPException):
pass

class OTPLoginFailed(OTPException):
pass

class OTPNotAuthenticated(OTPException):
pass

class OTPCodeNotSent(OTPException):
pass

class OTPSender:
"""
OTP sender class.

Attributes:
authenticated (bool): True if the user is authenticated, False otherwise.

Methods:
login() -> None:
Logs in to the SMTP server. Modifies the authenticated attribute.
send(to: str) -> str | None:
Sends a randomly generated OTP to the specified email address.
Returns the OTP sent to the specified email address.
R1D3R175 marked this conversation as resolved.
Show resolved Hide resolved
"""
def __init__(self):
try:
self.__server = smtplib.SMTP_SSL(HOST, smtplib.SMTP_SSL_PORT)
except Exception as e:
raise OTPConnectionFailed('Connection failed.') from e

self.authenticated = False
self.login()

def login(self) -> None:
"""
Logs in to the SMTP server.

Returns:
None: check self.authenticated for login status.
R1D3R175 marked this conversation as resolved.
Show resolved Hide resolved
"""
if self.authenticated:
return

try:
self.__server.login(USER, PASSWORD)
self.authenticated = True
except Exception as e:
raise OTPLoginFailed('Login failed.') from e

def send(self, to: str) -> str:
"""
Sends a randomly generated OTP to the specified email address.

Args:
to (str): The email address of the recipient.

Returns:
str: The OTP sent to the specified email address.
"""
if not self.authenticated:
raise OTPNotAuthenticated('Not authenticated.')

random.seed(os.urandom(64))
otp = str(random.randint(100000, 999999))

message = MIMEText(MAIL_TEMPLATE.format(otp=otp))
message['From'] = USER
message['To'] = to
message['Subject'] = "FinderUniCT-Bot - Codice OTP"

try:
self.__server.send_message(message)
return otp
except Exception as e:
raise OTPCodeNotSent('OTP code not sent.') from e