CSRSA/CSRSA_server.py
2025-03-28 18:32:31 +03:00

143 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import socket
import threading
import rsa
from datetime import datetime
class Server:
def __init__(self, host='0.0.0.0', port=5555):
self.host = host
self.port = port
self.clients = {}
self.public_keys = {}
self.server_public_key = None
self.server_private_key = None
self.generate_keys()
self.setup_server()
def generate_keys(self):
(self.server_public_key, self.server_private_key) = rsa.newkeys(2048)
def setup_server(self):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((self.host, self.port))
self.server.listen()
def broadcast(self, message, sender=None):
for client in self.clients:
if client != sender:
try:
client_public_key = self.public_keys[client]
encrypted_msg = rsa.encrypt(message.encode(), client_public_key)
client.send(encrypted_msg)
except:
self.remove_client(client)
def handle_client(self, client):
try:
# Отправляем клиенту публичный ключ сервера
client.send(self.server_public_key.save_pkcs1())
# Получаем публичный ключ клиента
client_public_key = rsa.PublicKey.load_pkcs1(client.recv(2048))
self.public_keys[client] = client_public_key
# Получаем имя клиента
encrypted_name = client.recv(1024)
client_name = rsa.decrypt(encrypted_name, self.server_private_key).decode()
self.clients[client] = client_name
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {client_name} подключился.")
self.broadcast(f"[СЕРВЕР] {client_name} присоединился к чату!", client)
while True:
try:
encrypted_msg = client.recv(4096)
if not encrypted_msg:
break
msg = rsa.decrypt(encrypted_msg, self.server_private_key).decode()
if msg.startswith('/file'):
self.handle_file_transfer(client, msg)
else:
self.broadcast(f"{self.clients[client]}: {msg}", client)
except Exception as e:
print(f"[ОШИБКА] {e}")
break
except Exception as e:
print(f"[ОШИБКА] {e}")
finally:
self.remove_client(client)
def handle_file_transfer(self, sender, command):
try:
parts = command.split(' ', 3)
if len(parts) < 4:
return
recipient_name = parts[1]
file_name = parts[2]
file_data = parts[3].encode()
# Находим получателя
recipient = None
for client in self.clients:
if self.clients[client] == recipient_name:
recipient = client
break
if recipient:
# Отправляем уведомление получателю
notification = f"/file_notification {self.clients[sender]} {file_name}"
encrypted_notification = rsa.encrypt(notification.encode(), self.public_keys[recipient])
recipient.send(encrypted_notification)
# Ждем подтверждения
response = rsa.decrypt(recipient.recv(1024), self.server_private_key).decode()
if response == "/accept_file":
# Отправляем файл
encrypted_file_data = rsa.encrypt(file_data, self.public_keys[recipient])
recipient.send(encrypted_file_data)
sender.send(rsa.encrypt(f"[СЕРВЕР] Файл {file_name} отправлен {recipient_name}".encode(),
self.public_keys[sender]))
else:
sender.send(rsa.encrypt(f"[СЕРВЕР] {recipient_name} отказался принять файл".encode(),
self.public_keys[sender]))
else:
sender.send(
rsa.encrypt(f"[СЕРВЕР] Пользователь {recipient_name} не найден".encode(), self.public_keys[sender]))
except Exception as e:
print(f"[ОШИБКА при передаче файла] {e}")
def remove_client(self, client):
if client in self.clients:
name = self.clients[client]
del self.clients[client]
if client in self.public_keys:
del self.public_keys[client]
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {name} отключился.")
self.broadcast(f"[СЕРВЕР] {name} покинул чат.", client)
client.close()
def run(self):
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Сервер запущен на {self.host}:{self.port}")
try:
while True:
client, address = self.server.accept()
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] Новое соединение с {address[0]}:{address[1]}")
thread = threading.Thread(target=self.handle_client, args=(client,))
thread.start()
except KeyboardInterrupt:
print("\nСервер останавливается...")
finally:
self.server.close()
if __name__ == "__main__":
server = Server()
server.run()