Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[MESSAGES CONTROL]
max-positional-arguments=10
disable=R0913,R0911,W0718,W0719,R0902,R0904,R0917,R0801
disable=R0913,R0911,W0718,W0719,R0902,R0904,R0917,R0801,R0914
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ auth = Auth(
"username": "your_email@example.com",
"password": "your_email_password"
}, # Optional: Include if using email verification
mail_subject="Verification Code", # Optional: Custom subject for verification codes
mail_body="Your verification code is: {verifcode}", # Optional: Custom email body for verification codes. The text verifcode in brackets is replaced with the code. Use HTML or plain text.
blocking=True/False, # Optional: True to enable user blocking
rate_limiting=0, # Optional: Set to 0 to disable rate limiting, or a positive integer to enable rate limiting with that cooldown period in seconds between user requests.
penalty=0, # Optional: Set to 0 to disable rate limiting penalty, or a positive integer to set the penalty in seconds for rate limiting. If rate limiting is enabled, this is the penalty in seconds added to the cooldown period for violating the cooldown.
Expand Down
21 changes: 17 additions & 4 deletions src/easy_mongodb_auth_handler/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,21 @@ def __init__(self, mongo_uri, db_name, mail_info=None,
db_name (str): Name of the database.
mail_info (dict, optional): Email server configuration with keys:
'server', 'port', 'username', 'password'.
mail_subject (str, optional): Custom email subject template.
Use {verifcode} placeholder for verification code.
Defaults to "Verification Code".
mail_body (str, optional): Custom email body template.
Use {verifcode} placeholder for verification code.
Supports both plain text and HTML.
Defaults to "Your verification code is: {verifcode}".
blocking (bool): Enable user blocking.
rate_limit (int): Rate limit for user actions in seconds.
penalty (int): Penalty time in seconds for rate limiting.
readable_errors (bool): Use readable error messages.
attempts (int): Number of connection attempts.
delay (int): Delay between connection attempts in seconds.
timeout (int): Timeout in milliseconds for MongoDB connection.
certs (str): Path to CA bundle for SSL verification.
"""
self.db = None
self.retry_count = 0
Expand Down Expand Up @@ -293,7 +302,8 @@ def register_user(self, email, password, custom_data=None,
self.blocked.insert_one({"email": email, "blocked": False})
hashed_password = hash_password(password)
verification_code = generate_secure_code()
send_verification_email(self.mail_info, email, verification_code)
send_verification_email(self.mail_info, email, verification_code,
self.mail_subject, self.mail_body)
self.users.insert_one(
{
"email": email,
Expand Down Expand Up @@ -341,7 +351,8 @@ def register_user_no_pass(self, email, custom_data=None,
else:
self.blocked.insert_one({"email": email, "blocked": False})
verification_code = generate_secure_code()
send_verification_email(self.mail_info, email, verification_code)
send_verification_email(self.mail_info, email, verification_code,
self.mail_subject, self.mail_body)
self.users.insert_one(
{
"email": email,
Expand Down Expand Up @@ -413,7 +424,8 @@ def authenticate_user(self, email, password, mfa=False,
{"email": email},
{"$set": {"verification_code": verification_code}}
)
send_verification_email(self.mail_info, email, verification_code)
send_verification_email(self.mail_info, email, verification_code,
self.mail_subject, self.mail_body)
return {"success": True, "message": self.messages["authentication_success"]}
return {"success": False, "message": self.messages["invalid_creds"]}
except Exception as error:
Expand Down Expand Up @@ -547,7 +559,8 @@ def generate_code(self, email, ignore_rate_limit=False):
return {"success": False, "message": self.messages["rate_limited"]}
reset_code = generate_secure_code()
self.users.update_one({"email": email}, {"$set": {"verification_code": reset_code}})
send_verification_email(self.mail_info, email, reset_code)
send_verification_email(self.mail_info, email, reset_code,
self.mail_subject, self.mail_body)
return {"success": True, "message": self.messages["verification_code_sent"]}
except Exception as error:
return {"success": False, "message": str(error)}
Expand Down
51 changes: 44 additions & 7 deletions src/easy_mongodb_auth_handler/package_functions/func.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import re
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import bcrypt


Expand Down Expand Up @@ -79,14 +80,18 @@ def validate_email(email):
return re.match(email_regex, email) is not None


def send_verification_email(mail_info, recipient_email, verification_code):
def send_verification_email(mail_info,
recipient_email, verification_code,
subject=None, body=None):
"""
sends a verification email with a specified code to the recipient

Args:
mail_info (dict): The server address, port, email address, and password.
recipient_email (str): The recipient's email address.
verification_code (str): The verification code to send.
subject (str, optional): Custom email subject. Uses default if None.
body (str, optional): Custom email body. Uses default if None.

Raises:
ValueError: If mail server settings are incomplete.
Expand All @@ -99,12 +104,44 @@ def send_verification_email(mail_info, recipient_email, verification_code):
if not all([mail_server, mail_port, mail_username, mail_password]):
raise ValueError("Mail server settings are incomplete or missing.")

subject = "Your Verification Code"
body = f"Your verification code is: {verification_code}"
msg = MIMEText(body)
msg["Subject"] = subject
msg["From"] = mail_username
msg["To"] = recipient_email
# Use default values if custom ones are not provided
if subject is None:
subject = "Verification Code"
if body is None:
body = "Your verification code is: {verifcode}"

# Replace verification code placeholder in both subject and body
final_subject = subject.replace("{verifcode}", verification_code)
final_body = body.replace("{verifcode}", verification_code)

# Check if body contains HTML tags to determine content type
is_html = any(tag in final_body.lower() for
tag in ['<html>', '<body>', '<p>', '<br>',
'<div>', '<span>'])
if is_html:
# Create multipart message for HTML content
msg = MIMEMultipart('alternative')
msg["Subject"] = final_subject
msg["From"] = mail_username
msg["To"] = recipient_email

# Create plain text version by removing HTML tags (simple approach)
plain_text = re.sub(r'<[^>]+>', '', final_body)
plain_text = re.sub(r'\s+', ' ', plain_text).strip()

# Create the text and HTML parts
text_part = MIMEText(plain_text, 'plain')
html_part = MIMEText(final_body, 'html')

# Add parts to message
msg.attach(text_part)
msg.attach(html_part)
else:
# Simple text message
msg = MIMEText(final_body)
msg["Subject"] = final_subject
msg["From"] = mail_username
msg["To"] = recipient_email

try:
with smtplib.SMTP(mail_server, mail_port) as server:
Expand Down