Merge pull request #5 from anorak999/fix/new-change
This commit is contained in:
commit
945d7aeb62
|
|
@ -40,7 +40,7 @@ class Client(RSAService, RichClientRenderer):
|
|||
return f"{self.ws_url}{path}"
|
||||
|
||||
def _connect_ws(self, path: str, retries: int = 5, backoff: float = 0.5):
|
||||
last_exc = None
|
||||
last_exc: Exception = ConnectionError("Failed to connect")
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
return create_connection(self._ws_full(path))
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class CryptoService(ABC):
|
|||
raise NotImplementedError("Need to implement generate keys method")
|
||||
|
||||
@abstractmethod
|
||||
def _get_generated_keys(self) -> list[str]:
|
||||
def _get_generated_keys(self) -> tuple:
|
||||
raise NotImplementedError("Need to implement get generated keys method")
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
|||
|
|
@ -2,23 +2,33 @@ from abc import ABC, abstractmethod
|
|||
|
||||
|
||||
class ClientRenderer(ABC):
|
||||
# These attributes are expected to be provided by subclasses
|
||||
# (typically via multiple inheritance with CryptoService)
|
||||
username: str
|
||||
|
||||
@abstractmethod
|
||||
def _decrypt(self, message: str) -> str:
|
||||
"""Decrypt an encrypted message (provided by crypto mixin)."""
|
||||
raise NotImplementedError("Need to implement _decrypt")
|
||||
|
||||
@abstractmethod
|
||||
def print_message(self, message: str) -> str:
|
||||
raise NotImplementedError("Need to implement print_message")
|
||||
|
||||
@abstractmethod
|
||||
def clear_console(self, message: str) -> str:
|
||||
def clear_console(self) -> None:
|
||||
"""Clear the client console (platform-specific)."""
|
||||
raise NotImplementedError("Need to implement clear_console")
|
||||
|
||||
@abstractmethod
|
||||
def print_ip(self, url: str, username: str):
|
||||
def print_ip(self, ip: str) -> str:
|
||||
raise NotImplementedError("Need to implement print_ip")
|
||||
|
||||
@abstractmethod
|
||||
def print_username(self):
|
||||
def print_username(self, username: str) -> str:
|
||||
raise NotImplementedError("Need to implement print_username")
|
||||
|
||||
@abstractmethod
|
||||
def print_chat(self) -> list[str]:
|
||||
def print_chat(self, response) -> None:
|
||||
"""Render chat payload (response is expected to be a mapping with 'messages' and 'users_in_chat')."""
|
||||
raise NotImplementedError("Need to implement print_chat")
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ class RSAService(CryptoService):
|
|||
stream=True,
|
||||
)
|
||||
r.raise_for_status()
|
||||
message = r.raw.read(999)
|
||||
# read the full response content (server returns encrypted symmetric key)
|
||||
message = r.content
|
||||
self.symmetric_key = rsa.decrypt(message, self.private_key)
|
||||
self.fernet = Fernet(self.symmetric_key)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,11 @@ class DefaultClientRenderer(ClientRenderer):
|
|||
def print_message(self, message: str) -> str:
|
||||
""" generating string with message in required format
|
||||
"""
|
||||
message = message.split(":")
|
||||
if message[0] == self.username:
|
||||
return COLORS["my_username_color"] + message[0] + ": " + message[1] + COLORS["text_color"]
|
||||
return message[0] + ": " + message[1] + COLORS["text_color"]
|
||||
# split only on the first ':' to keep message contents intact
|
||||
parts = message.split(":", 1)
|
||||
if parts[0] == self.username:
|
||||
return COLORS["my_username_color"] + parts[0] + ": " + parts[1] + COLORS["text_color"]
|
||||
return parts[0] + ": " + parts[1] + COLORS["text_color"]
|
||||
|
||||
def clear_console(self):
|
||||
# For windows clear command its cls
|
||||
|
|
@ -44,9 +45,10 @@ class DefaultClientRenderer(ClientRenderer):
|
|||
self,
|
||||
username: str
|
||||
) -> str:
|
||||
return f"USERNAME: " + COLORS["ip_color"] + username + COLORS["username_color"]
|
||||
# Username label + colored username
|
||||
return f"USERNAME: " + COLORS["username_color"] + username + COLORS["text_color"]
|
||||
|
||||
def print_chat(self, response: list[str]) -> str:
|
||||
def print_chat(self, response) -> None:
|
||||
for i, msg in enumerate(response["messages"]):
|
||||
actual_message = self._decrypt(msg)
|
||||
if i == 0:
|
||||
|
|
|
|||
|
|
@ -25,16 +25,17 @@ class RichClientRenderer(ClientRenderer):
|
|||
def print_message(self, message: str) -> Text:
|
||||
""" generating string with message in required format
|
||||
"""
|
||||
message = message.split(":")
|
||||
if message[0] == self.username:
|
||||
# split only on the first ':' so message bodies containing ':' are preserved
|
||||
parts = message.split(":", 1)
|
||||
if parts[0] == self.username:
|
||||
return \
|
||||
Text(text=message[0], style="bold") + \
|
||||
Text(text=parts[0], style="bold") + \
|
||||
Text(text=": ", style="bold") + \
|
||||
Text(text=message[1], style="underline")
|
||||
Text(text=parts[1], style="underline")
|
||||
return \
|
||||
Text(text=message[0], style="bold") + \
|
||||
Text(text=parts[0], style="bold") + \
|
||||
Text(text=": ", style="bold") + \
|
||||
Text(text=message[1], style="underline")
|
||||
Text(text=parts[1], style="underline")
|
||||
|
||||
def clear_console(self):
|
||||
# For windows clear command its cls
|
||||
|
|
@ -56,7 +57,7 @@ class RichClientRenderer(ClientRenderer):
|
|||
) -> str:
|
||||
return username
|
||||
|
||||
def print_chat(self, response: list[str]) -> str:
|
||||
def print_chat(self, response) -> None:
|
||||
self.clear_console()
|
||||
for i, msg in enumerate(response["messages"][-MESSAGES_TO_SHOW:]):
|
||||
actual_message = self._decrypt(msg)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@ def attach_endpoints(app: Sanic):
|
|||
while True:
|
||||
serialized_message: dict = await _get_bytes_and_serialize(ws)
|
||||
await _check_ws_for_close_status(serialized_message, ws)
|
||||
new_message = await _generate_new_message(serialized_message.get("text"))
|
||||
text = serialized_message.get("text")
|
||||
if text is None:
|
||||
continue
|
||||
new_message = await _generate_new_message(text)
|
||||
MESSAGES_MEMORY_DB.append(new_message)
|
||||
await ws.send(str({"status": "ok"}))
|
||||
await asyncio.sleep(0.2)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ async def _generate_new_message(
|
|||
|
||||
|
||||
async def _generate_update_payload(
|
||||
memory_msgs: list[str],
|
||||
memory_msgs: list[Message],
|
||||
users_structure: dict
|
||||
) -> str:
|
||||
return str({
|
||||
|
|
|
|||
13
setup.py
13
setup.py
|
|
@ -1,20 +1,15 @@
|
|||
import setuptools
|
||||
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
description = fh.read()
|
||||
|
||||
|
||||
setuptools.setup(
|
||||
name="secured_console_chat",
|
||||
version="1.1.22",
|
||||
author="dinosaurtirex",
|
||||
author_email="sneakybeaky18@gmail.com",
|
||||
packages=[
|
||||
"cmd_chat",
|
||||
"cmd_chat/client",
|
||||
"cmd_chat/client/core",
|
||||
"cmd_chat/client/core/abs",
|
||||
"cmd_chat/server"
|
||||
],
|
||||
# Use find_packages to correctly discover package names
|
||||
packages=setuptools.find_packages(exclude=("tests", "docs")),
|
||||
description="Secured console chat with RSA & Fernet",
|
||||
long_description=description,
|
||||
long_description_content_type="text/markdown",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user