-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
166 lines (141 loc) · 5.84 KB
/
server.py
File metadata and controls
166 lines (141 loc) · 5.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import socket
import threading
import json
from crypto_utils import hash_password, verify_password
from crypto_utils import encrypt_message, derive_key, decrypt_message
import os
from message_logger import log_message, clear_log
from client import ChatClient
global self
key = derive_key("your_shared_secret")
class ChatServer:
def __init__(self, host='localhost', port=5555):
self.host = host
self.client_keys = {}
self.port = port
self.key = derive_key("your_shared_secret")
clear_log()
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.clients = {}
self.users_db = 'users.json'
self.load_users()
def load_users(self):
"""Load users from JSON file or create empty database"""
try:
with open(self.users_db, 'r') as f:
self.users = json.load(f)
except FileNotFoundError:
self.users = {}
self.save_users()
def save_users(self):
"""Save users to JSON file"""
with open(self.users_db, 'w') as f:
json.dump(self.users, f)
def broadcast(self, message, sender_socket=None):
"""Send message to all clients except sender"""
for client in self.clients:
if client != sender_socket:
try:
client.send(message.encode())
except:
self.remove_client(client)
def remove_client(self, client_socket):
"""Remove client from active clients"""
if client_socket in self.clients:
username = self.clients[client_socket]
del self.clients[client_socket]
self.broadcast(f"Server: {username} left the chat")
client_socket.close()
# In server.py
def handle_client(self, client_socket, addr):
"""Handle individual client connection"""
print(f"New connection from {addr}")
while True:
try:
message = client_socket.recv(4096).decode()
if not message:
break
if message.startswith('/register'):
self.handle_registration(client_socket, message)
elif message.startswith('/login'):
self.handle_login(client_socket, message)
elif message.startswith('/quit'):
break
else:
if client_socket in self.clients:
username = self.clients[client_socket]
try:
# Log the detailed format to file
#with open('message_log.txt', 'a') as log_file:
#log_file.write(f"{username} : {message}:\n")
broadcast_message = f"{username}: {message}"
self.broadcast(broadcast_message, client_socket)
except Exception as e:
print(f"Error processing message: {e}")
else:
client_socket.send("Please login first".encode())
except ConnectionResetError:
print(f"Client {addr} disconnected unexpectedly")
break
except Exception as e:
print(f"Error handling client {addr}: {e}")
break
self.remove_client(client_socket)
print(f"Connection closed: {addr}")
def handle_registration(self, client_socket, message):
"""Handle user registration"""
try:
_, username, password = message.split()
if username in self.users:
client_socket.send("/register_fail".encode())
return
salt, hash_value = hash_password(password)
self.users[username] = {
'salt': salt,
'hash': hash_value
}
self.save_users()
client_socket.send("/register_success".encode())
except Exception as e:
print(f"Registration error: {e}")
client_socket.send("/register_fail".encode())
def handle_login(self, client_socket, message):
"""Handle user login"""
try:
_, username, password = message.split()
if username not in self.users:
client_socket.send("/login_fail".encode())
return
user_data = self.users[username]
if verify_password(password, user_data['salt'], user_data['hash']):
self.clients[client_socket] = username
client_socket.send("/login_success".encode())
self.broadcast(f"Server: {username} joined the chat", client_socket)
else:
client_socket.send("/login_fail".encode())
except Exception as e:
print(f"Login error: {e}")
client_socket.send("/login_fail".encode())
def start(self):
"""Start the server"""
self.server_socket.bind((self.host, self.port))
self.server_socket.listen(5)
print(f"Server started on {self.host}:{self.port}")
try:
while True:
client_socket, addr = self.server_socket.accept()
print(f"New connection from {addr}")
client_thread = threading.Thread(
target=self.handle_client,
args=(client_socket, addr)
)
client_thread.daemon = True
client_thread.start()
except KeyboardInterrupt:
print("\nShutting down server...")
finally:
self.server_socket.close()
if __name__ == "__main__":
server = ChatServer()
server.start()