143 lines
5.7 KiB
Python
143 lines
5.7 KiB
Python
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() |