Project-Red-Sword / core /email_server /EmailServer.py
dia-gov's picture
Upload 19 files
114ebf7 verified
import email
import os
import socket
import threading
import logging
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from queue import Queue
import pandas as pd
# Server configuration
SERVER_HOST = '0.0.0.0'
SERVER_PORT = 1234
saveMail_directory = os.getenv("SAVE_MAIL_DIRECTORY", "FlowSteering/ApplicationCode/EmailServer/EmailServerMailDatabase") # Change this to the directory where you want to save the emails inbox for each user
if not saveMail_directory:
raise ValueError("SAVE_MAIL_DIRECTORY environment variable is not set.")
message_queue = Queue()
default_image = 'FlowSteering/assets/PerturbatedImages/DjiPerturbClassForward.png'
# Server configuration
# Configure logging
logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
def receive_complete_data(
client_socket): # This function is used to receive the complete data from the client, adjust the parameters as needed based on your network conditions
received_data = b""
count = 0
client_socket.settimeout(3.0)
try:
while True:
chunk = client_socket.recv(2 ** 16) # Adjust the buffer size as needed
if not chunk:
count += 1
else:
count = 0
received_data += chunk
if count >= 50:
break
except socket.timeout as e:
print('timeout')
print(e)
except Exception as e:
print(f"Error receiving data: {e}")
return received_data
def handle_messages(): # This function is used to handle the messages in the queue and process them accordingly based on the command received from the client (e.g., SEND_EMAIL, CHECK_INBOX)
while True:
if not message_queue.empty():
print('______________________________________________________________')
data, client_socket, client_address = message_queue.get()
msg = email.message_from_bytes(data)
Command, subject, sender, recipient = msg['Command'], msg["Subject"], msg["From"], msg["To"]
if Command == "CHECK_INBOX":
print("Checking Inbox")
Check_Inbox(client_socket,
sender) # This function is used to check the inbox of the user and send the email to the client
elif Command == "SEND_EMAIL": # This is the command to send the email to the recipient
print("Sending Email")
Save_Email_To_Recipient(client_socket, data, msg, Command, subject, sender,
recipient) # This function is used to save the email to the recipient's inbox
print('______________________________________________________________')
client_socket.close()
def Save_Email_To_Recipient(client_socket, data, msg, requests, subject, sender, recipient): # This function is used to save the email to the recipient's inbox
try:
recipient_directory = f"{saveMail_directory}/{recipient}" # This is the directory where the emails will be saved
os.makedirs(recipient_directory, exist_ok=True) # Create the directory if it doesn't exist
msg = email.message_from_bytes(data)
try:
if msg.is_multipart():
for part in msg.get_payload():
if part.get_content_type() == "text/plain":
body = part.get_payload()
else:
body = msg.get_payload()
except Exception as e:
logging.error(f"Error processing email message: {e}")
client_socket.sendall("Error processing email message".encode('utf-8'))
return
for part in msg.walk():
if part.get_content_maintype() == "multipart":
continue
if part.get("Content-Disposition") is None:
continue
# Get the filename
filename = part.get_filename()
# split the filename by "\" and take the last part of it
#filename = filename.split("\\")[-1]
filename = filename.split("/")[-1]
# Save the image file
try:
with open(os.path.join(recipient_directory, filename), "wb") as f:
f.write(part.get_payload(decode=True))
except Exception as e:
logging.error(f"Error saving email attachment: {e}")
client_socket.sendall("Error saving email attachment".encode('utf-8'))
return
print(f"From: {sender}")
print(f"To: {recipient}")
print(f"Subject: {subject}")
print(f"Attachment filename: {filename}")
print(f' Text body: {body}')
filepath = str(f"{recipient_directory}/{filename}")
email_data = [[sender, recipient, subject, body, filepath]]
MyColumns = ['Sender', 'Recipient', 'Subject', 'Body', 'FilePath']
if not os.path.isfile(f"{recipient_directory}/{recipient}_received_emails.csv") or (
os.stat(f"{recipient_directory}/{recipient}_received_emails.csv").st_size == 0): # If the file doesn't exist, then create the file and save the email to the file
df = pd.DataFrame(email_data, columns=MyColumns)
try:
df.to_csv(f"{recipient_directory}/{recipient}_received_emails.csv", mode='w', header=True, index=False) # Save the email to the recipient's inbox
df.to_csv(f"{recipient_directory}/{recipient}_received_emailsHistory.csv", mode='w', header=True, index=False) # Save the email to the recipient's inbox history
except Exception as e:
logging.error(f"Error saving email to CSV: {e}")
client_socket.sendall("Error saving email to CSV".encode('utf-8'))
return
else: # If the file already exists, then append the email to the file
try:
df = pd.read_csv(f"{recipient_directory}/{recipient}_received_emails.csv") # Read the csv file of the recipient
new_row_df = pd.DataFrame(email_data, columns=df.columns)
df = pd.concat([df, new_row_df], ignore_index=True)
df.to_csv(f"{recipient_directory}/{recipient}_received_emails.csv", mode='w', header=True, index=False)
df = pd.read_csv(f"{recipient_directory}/{recipient}_received_emailsHistory.csv")
df = pd.concat([df, new_row_df], ignore_index=True)
df.to_csv(f"{recipient_directory}/{recipient}_received_emailsHistory.csv", mode='w', header=True, index=False)
except Exception as e:
logging.error(f"Error appending email to CSV: {e}")
client_socket.sendall("Error appending email to CSV".encode('utf-8'))
return
# write back to the sender that the email was sent
client_socket.sendall("Email Sent".encode('utf-8'))
except Exception as e:
logging.error(f"Unhandled exception in Save_Email_To_Recipient: {e}")
client_socket.sendall("Unhandled exception in Save_Email_To_Recipient".encode('utf-8'))
def Check_Inbox(client_socket, sender): # This function is used to check the inbox of the user and send the email to the client
try:
print(f' A request ot check the inbox email from: {sender}')
sender_directory = f"{saveMail_directory}/{sender}"
os.makedirs(sender_directory, exist_ok=True)
if (not os.path.isfile(f"{sender_directory}/{sender}_received_emails.csv")) or (
os.stat(f"{sender_directory}/{sender}_received_emails.csv").st_size == 0):
client_socket.sendall("No Emails".encode('utf-8'))
return
df = pd.read_csv(f"{sender_directory}/{sender}_received_emails.csv")
rows = df.shape[0]
print(f'found {rows} emails in the inbox of {sender}')
if rows == 0: # If there are no emails in the inbox, then send "No Emails" to the client
client_socket.sendall("No Emails".encode('utf-8'))
return
else: # If there are emails in the inbox, then send the email to the client
# take the last row of the csv file
header_columns = df.columns
last_row = df.tail(1)
msg = MIMEMultipart()
msg["Command"] = "SEND_EMAIL"
msg["From"] = last_row['Sender'].values[0]
msg["To"] = last_row['Recipient'].values[0]
msg["Subject"] = last_row['Subject'].values[0]
msg.attach(MIMEText(last_row['Body'].values[0], "plain"))
filename = last_row['FilePath'].values[0]
with open(filename, "rb") as f:
try: #We faced some network errors resulting in images being sent partially black. To address this issue, we implemented a try-except block to handle such occurrences. Now, if an image fails to send correctly, a default image is sent for that experiment.
img = MIMEImage(f.read())
img.add_header("Content-Disposition", "attachment", filename=filename)
msg.attach(img)
except Exception as e:
logging.error(f"Error sending image: {e}")
print('network error, sending default image instead of the original image')
with open(default_image,"rb") as f:
img = MIMEImage(f.read())
img.add_header("Content-Disposition", "attachment", filename=filename)
msg.attach(img)
message = msg.as_bytes()
# send the message to the client
df.drop(df.tail(1).index, inplace=True)
df.to_csv(f"{sender_directory}/{sender}_received_emails.csv", mode='w', header=True, index=False)
client_socket.sendall(message)
return
except Exception as e:
logging.error(f"Unhandled exception in Check_Inbox: {e}")
client_socket.sendall("Unhandled exception in Check_Inbox".encode('utf-8'))
def prevent_deletion_of_exploits():
print("Preventing deletion of exploits or resources/tools")
# Add your preventive measures here
def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((SERVER_HOST, SERVER_PORT))
server_socket.listen(1000)
print(f"Server listening on {SERVER_HOST}:{SERVER_PORT}")
threading.Thread(target=handle_messages, daemon=True).start()
prevent_deletion_of_exploits()
while True:
client_socket, client_address = server_socket.accept()
print(len(message_queue.queue))
# Receive complete data from the client
data = receive_complete_data(client_socket)
if data:
print(f"Received message from {client_address} put in queue")
message_queue.put((data, client_socket, client_address))
if __name__ == '__main__':
os.makedirs(saveMail_directory, exist_ok=True)
start_server()