Skip to content

Commit 53c560d

Browse files
committed
first commit
0 parents  commit 53c560d

File tree

5 files changed

+253
-0
lines changed

5 files changed

+253
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<h1 align="center">
2+
Python P2P Crypt Chat App
3+
</h1>
4+
5+
<h4 align="center">Chat over <a href="https://en.wikipedia.org/wiki/Berkeley_sockets">Berkeley Sockets</a> with encryption, p2p and over internet (needs port fowarding).</h4>
6+
7+
<p align="center">
8+
<a href="#about">About</a> •
9+
<a href="#features">Features</a> •
10+
<a href="#usage">Usage</a> •
11+
<a href="#credits">Credits</a> •
12+
<a href="#license">License</a>
13+
</p>
14+
15+
![cefet](https://i.imgur.com/K0E5iFC.jpg)
16+
17+
## About
18+
19+
This is a simple python program made for university work. It uses python socket, threads and a encryption package. This program uses P2P and client-server architecture.
20+
21+
## Features
22+
23+
* Interactive Chat
24+
* Send and view replies.
25+
* Multi-client
26+
* Create a lobby with your friends
27+
* P2P
28+
* Run your own server and client to make a direct connection with another clients
29+
* Encryption
30+
* Make your messages safe with [fernet](https://github.com/pyca/cryptography).
31+
32+
## Usage
33+
34+
To run this program you will need [git](https://git-scm.com/), [python](https://www.python.org/), [request](https://github.com/psf/requests), [cryptography](https://github.com/pyca/cryptography). On your console:
35+
36+
```bash
37+
# Clone the repository
38+
git clone https://github.com/cassiofb-dev/python-p2p-crypt-chat
39+
40+
# Go inside
41+
cd python-p2p-crypt-chat
42+
43+
# Install dependencies
44+
pip install requests
45+
pip install cryptography
46+
47+
# run application
48+
py p2p.py
49+
```
50+
51+
## Credits
52+
53+
This app uses the following open source projects:
54+
55+
* [Git](https://github.com/git/git)
56+
* [Python](https://www.python.org/)
57+
* [Requests](https://github.com/psf/requests)
58+
* [Cryptography](https://github.com/pyca/cryptography)
59+
60+
## License
61+
62+
MIT
63+
64+
---
65+
66+
> [Acesse meu site](https://cassiofernando.netlify.app/) &nbsp;&middot;&nbsp;
67+
> GitHub [@cassiofb-dev](https://github.com/cassiofb-dev) &nbsp;&middot;&nbsp;
68+
> Twitter [@cassiofb_dev](https://twitter.com/cassiofb_dev)

client.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import socket, os
2+
from cryptography.fernet import Fernet
3+
4+
class Client():
5+
def __init__(self, server_url=socket.gethostbyname(socket.gethostname()), server_port="25565"):
6+
self.server_url = server_url
7+
self.server_port = int(server_port)
8+
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
9+
self.connected = False
10+
self.fernet = None
11+
12+
def send_message(self):
13+
client_message = input("enter a message >> ")
14+
self.client_socket.send(self.encode_message(client_message))
15+
16+
def exit(self):
17+
self.client_socket.send(self.encode_message("3"))
18+
self.client_socket.close()
19+
self.connected = False
20+
21+
def init_crypt_service(self):
22+
fernet_key = bytes(input("enter fernet key >> "), "utf-8")
23+
self.fernet =Fernet(fernet_key)
24+
self.client_socket.send(bytes("4", "utf-8"))
25+
26+
def start(self):
27+
self.client_socket.connect((self.server_url, self.server_port))
28+
self.connected = True
29+
while self.connected:
30+
print("esperando mensagem...")
31+
server_message = self.decode_message(self.client_socket.recv(4096))
32+
os.system('cls' if os.name == 'nt' else 'clear')
33+
print(f"{server_message}")
34+
user_input = input(f"(1) send message, (2) refresh chat, (3) exit{', (4) start crypt service ' if self.fernet == None else ' '}>> ")[0]
35+
if user_input == "1": self.send_message()
36+
elif user_input == "2": self.client_socket.send(self.encode_message("2"))
37+
elif user_input == "3": self.exit()
38+
elif user_input == "4": self.init_crypt_service()
39+
else: self.exit()
40+
41+
def encode_message(self, message: str):
42+
bytes_message = bytes(message, "utf-8")
43+
coded_message = bytes_message if self.fernet == None else self.fernet.encrypt(bytes_message)
44+
return coded_message
45+
46+
def decode_message(self, bytes_message: bytes):
47+
print(f"message: {bytes_message.decode()}")
48+
decoded_message = (bytes_message if self.fernet == None else self.fernet.decrypt(bytes_message)).decode()
49+
return decoded_message
50+
51+
if __name__ == "__main__":
52+
custom_config = input("custom config? (s/n) >> ")[0] == "s"
53+
client = Client() if custom_config == False else Client(input("enter server hostname >> "), input("enter server port >> "))
54+
client.start()

p2p.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import time, socket
2+
from client import Client
3+
from server import Server
4+
5+
def init_server(): Server().start()
6+
def init_client(): Client(input("client: enter server hostname >> "), input("client: enter server port >> ")).start()
7+
8+
def init_p2p_default(
9+
server_use_crypto=False,
10+
server_port_for_server="25565",
11+
server_hostname_for_client=socket.gethostbyname(socket.gethostname()),
12+
server_port_for_client="25565",
13+
):
14+
server = Server(server_port=server_port_for_server, use_crypt=server_use_crypto)
15+
client = Client(server_hostname_for_client, server_port_for_client)
16+
17+
server.start()
18+
while server.server_started == False: time.sleep(0.2)
19+
input("p2p: server started, press any key to start client...")
20+
client.start()
21+
22+
def init_p2p_custom(): init_p2p_default(
23+
server_use_crypto=input("type (1) to encrypt server >> ") == "1",
24+
server_port_for_server=input("server: enter port >> "),
25+
server_hostname_for_client=input("client: enter server hostname >> "),
26+
server_port_for_client=input("client: enter server port >> "),
27+
)
28+
29+
def init_p2p():
30+
user_input = input("(1) client mode, (2) server mode, (3) p2p default mode, (4) p2p custom mode >> ")[0]
31+
if user_input == "1": init_client()
32+
elif user_input == "2": init_server()
33+
elif user_input == "3": init_p2p_default()
34+
elif user_input == "4": init_p2p_custom()
35+
36+
if __name__ == "__main__": init_p2p()

server.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import socket, threading, requests, time, os
2+
from cryptography.fernet import Fernet
3+
4+
class ClientThread(threading.Thread):
5+
def __init__(self, client_socket: socket.socket, client_address: tuple[str, int], server: "Server"):
6+
threading.Thread.__init__(self)
7+
self.client_socket = client_socket
8+
self.client_address = client_address
9+
self.server = server
10+
self.username = "no_username"
11+
self.has_to_start_crypt_service = self.server.server_use_crypt
12+
self.has_to_send_username = True
13+
14+
def run(self):
15+
client_message = None
16+
while True:
17+
if self.has_to_start_crypt_service:
18+
self.client_socket.send(bytes("server: fernet enabled, please start crypt service\n", "utf-8"))
19+
client_message = self.client_socket.recv(4096).decode()
20+
if client_message == "4": self.has_to_start_crypt_service = False
21+
elif self.has_to_send_username:
22+
self.client_socket.send(self.encode_message("server: connected to server, enter a username or send '1'\n"))
23+
client_message = self.decode_message(self.client_socket.recv(4096))
24+
if client_message != "1": self.username = client_message
25+
if client_message != "2":
26+
self.server.usernames.append(self.username)
27+
self.server.messages.append(f"server: ({self.username}) joined the chat")
28+
self.has_to_send_username = False
29+
else:
30+
self.send_server_chat()
31+
client_message = self.decode_message(self.client_socket.recv(4096))
32+
if client_message == "3": break
33+
client_username_message = f"({self.username}): {client_message}"
34+
if client_message != "2": self.server.messages.append(client_username_message)
35+
self.server.usernames.remove(self.username)
36+
self.server.messages.append(f"server: ({self.username}) left the chat")
37+
38+
def send_server_chat(self):
39+
server_message = ""
40+
server_message += f"server: your username is ({self.username}), have a nice chat\n"
41+
server_message += "\n".join(self.server.messages)
42+
server_message += f"\n\nserver: your username is: ({self.username}), there are ({len(self.server.usernames)}) online users"
43+
self.client_socket.send(self.encode_message(server_message))
44+
45+
46+
def encode_message(self, message: str):
47+
bytes_message = bytes(message, "utf-8")
48+
coded_message = bytes_message if self.server.server_fernet == None else self.server.server_fernet.encrypt(bytes_message)
49+
return coded_message
50+
51+
def decode_message(self, bytes_message: bytes):
52+
decoded_message = (bytes_message if self.server.server_fernet == None else self.server.server_fernet.decrypt(bytes_message)).decode()
53+
return decoded_message
54+
55+
class Server(threading.Thread):
56+
def __init__(self, server_url=socket.gethostbyname(socket.gethostname()), server_port="25565", use_crypt=False):
57+
threading.Thread.__init__(self)
58+
self.server_url = server_url
59+
self.server_port = int(server_port)
60+
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
61+
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
62+
self.server_started = False
63+
self.usernames = []
64+
self.messages = []
65+
self.server_use_crypt = use_crypt
66+
if self.server_use_crypt == False:
67+
self.server_fernet_key = None
68+
self.server_fernet = None
69+
else:
70+
self.server_fernet_key = Fernet.generate_key()
71+
self.server_fernet = Fernet(self.server_fernet_key)
72+
print(f"server starting on crypto mode, paste key for clients: {self.server_fernet_key.decode()}\n5 seconds to clear key and start server...")
73+
time.sleep(5)
74+
os.system('cls' if os.name == 'nt' else 'clear')
75+
76+
def run(self):
77+
self.server_socket.bind((self.server_url, self.server_port))
78+
print(f"server started on ({self.server_url}:{self.server_port})")
79+
print(f"server public ip: {requests.get('https://api.ipify.org').text}")
80+
self.server_started = True
81+
while True:
82+
self.server_socket.listen(1)
83+
client_socket, client_address = self.server_socket.accept()
84+
client_thread = ClientThread(client_socket, client_address, self)
85+
client_thread.start()
86+
87+
if __name__ == "__main__":
88+
custom_config = input("custom config? (s/n) >> ")[0] == "s"
89+
server = Server() if custom_config == False else Server(
90+
server_url=input("enter server hostname >> "),
91+
server_port=input("enter server port >> "),
92+
use_crypt=input("use encryption? (s/n) >> ")[0] == "s",
93+
)
94+
server.start()

0 commit comments

Comments
 (0)