diff --git a/CHANGELOG.md b/CHANGELOG.md index e1415b9..0af7216 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ This project uses Semantic Versioning +## 2.0.0 + +* Added full utf-8 support via base85 +* removed connection established message, apps can send that themselves (yam util does) + + ## 1.2.0 * finished basic client tests diff --git a/setup.py b/setup.py index d51fb8c..b47b29d 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: packages = find_packages(exclude=['contrib', 'docs', 'tests']) setup(name='youandme', - version='1.2.0', + version='2.0.0', description='Simple private data sharing via bytearrays, Tor tunneling and metadata paranoia', long_description=long_description, long_description_content_type='text/markdown', diff --git a/src/yam/yam.py b/src/yam/yam.py index e21214f..fa9fcd4 100644 --- a/src/yam/yam.py +++ b/src/yam/yam.py @@ -19,6 +19,7 @@ except ModuleNotFoundError: from youandme.commands import terminator from youandme.server import server from youandme.client import client +from youandme.stream import encode_and_send, decoded_recv_stream class Connection: @@ -82,7 +83,7 @@ def connector(host, send_data, recv_data, def chat(mode, send_data, recv_data, alpha): - print("A notice will be shown when connection is established," + + print("A notice will be shown when connection is established, " + "but messages may be typed now.") display_buffer = [] @@ -94,17 +95,32 @@ def chat(mode, send_data, recv_data, alpha): print(_Address.address) def display_new(): - for message in get_messages + buffer = [] + while True: + try: + for message in decoded_recv_stream(recv_data, 0.5): + if alpha: + for c in message: + c = c.decode('utf-8') + if c not in printable: + continue + if len(buffer) < 1000: + buffer.append(c) + print("\033[1;33m" + "".join(buffer) + "\033[0m") + else: + print("\033[1;33m" + message.decode('utf-8') + "\033[0m") + except ValueError: + pass + Thread(target=display_new, daemon=True).start() def make_message(): while True: new = input("\033[0m").encode('utf-8') # nosec - for b in new: - send_data.append(b) - send_data.append(ord(b"\n")) + encode_and_send(send_data, new) Thread(target=make_message, daemon=True).start() + encode_and_send(send_data, "Connection established") while True: try: if not Connection.connected: diff --git a/src/youandme/client.py b/src/youandme/client.py index f84f1a1..fedbb86 100644 --- a/src/youandme/client.py +++ b/src/youandme/client.py @@ -4,7 +4,6 @@ from time import sleep import socks from .commands import garbage_character -from .commands import WELCOME_MESSAGE def client(delay: int, hs_id: str, socks_port, send_data: bytearray, recv_data: bytearray, connection: "Connection"): @@ -16,8 +15,6 @@ def client(delay: int, hs_id: str, socks_port, send_data: bytearray, recv_data: hs_id += '.onion' def send_loop(): - for i in WELCOME_MESSAGE: - send_data.append(ord(i)) while True: to_send = None if send_data: diff --git a/src/youandme/server.py b/src/youandme/server.py index 1ff33cc..dffd573 100644 --- a/src/youandme/server.py +++ b/src/youandme/server.py @@ -7,7 +7,6 @@ if typing.TYPE_CHECKING: from stem.control import Controller from.commands import garbage_character -from.commands import WELCOME_MESSAGE def server(delay: int, controller: 'Controller', socket_conn, send_data: bytearray, recv_data: bytearray, connection: "Connection"): @@ -28,7 +27,6 @@ def server(delay: int, controller: 'Controller', socket_conn, send_data: bytearr socket_conn.sendall(chr(char).encode('utf-8')) except OSError: connection.connected = False - first_rec = True with socket_conn: Thread(target=send_loop, daemon=True).start() while True: @@ -38,10 +36,7 @@ def server(delay: int, controller: 'Controller', socket_conn, send_data: bytearr connection.connected = False break if not data: break - if first_rec: - for i in WELCOME_MESSAGE: - send_data.append(ord(i)) - first_rec = False + if data != garbage_character and data: for i in data: recv_data.append(i) diff --git a/src/youandme/stream.py b/src/youandme/stream.py index 55594b3..ec2bf7b 100644 --- a/src/youandme/stream.py +++ b/src/youandme/stream.py @@ -1,19 +1,33 @@ from base64 import b85encode, b85decode from time import sleep +import sys +from typing import Union from youandme.commands import terminator -_b85alphabet = (b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +_b85alphabet = bytearray(b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" b"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~") -def decoded_recv_stream(raw_stream: bytearray, delay_seconds: int, max_buffer_size=) -> bytes: +def decoded_recv_stream(raw_stream: bytearray, delay_seconds: int) -> bytes: while True: for byte in raw_stream: if byte == terminator: - yield b85decode(raw_stream[:len(raw_stream) - 1]) + raw_stream.pop() + yield b85decode(raw_stream) raw_stream.clear() continue - if byte not in _b85alphabet: - raise ValueError('Not valid base85 encoding') sleep(delay_seconds) + + +def encode_and_send(send_stream: bytearray, data: Union[bytes, str]): + try: + data = data.encode('utf-8') + except AttributeError: + pass + encoded = b85encode(data) + for c in encoded: + send_stream.append(c) + + send_stream.append(terminator) + diff --git a/tests/test_stream.py b/tests/test_stream.py index 3a9b09d..a93d279 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -14,6 +14,7 @@ def add_encoded_to_bytes_array_valid(message, array: bytearray): array.append(m) array.append(terminator) + class TestStream(unittest.TestCase): def test_stream_get(self): @@ -27,8 +28,36 @@ class TestStream(unittest.TestCase): c = 0 for message in stream.decoded_recv_stream(recv_data, 1): self.assertEqual(message.decode('utf-8'), data) + self.assertNotIn(terminator, message) break + def test_stream_send(self): + send_data = bytearray() + recv_data = bytearray() + data = "hello world" + data_bytes = data.encode('utf-8') + encoded = b85encode(data_bytes) + + stream.encode_and_send(send_data, data) + for i in send_data: + if i != terminator: + self.assertIn(chr(i).encode('utf-8'), encoded) + + self.assertEqual(data_bytes, b85decode(send_data[:len(send_data) - 1])) + + + def test_stream_send_has_terminator(self): + send_data = bytearray() + recv_data = bytearray() + data = "hello world" + data_bytes = data.encode('utf-8') + encoded = b85encode(data_bytes) + + stream.encode_and_send(send_data, data) + + self.assertEqual(send_data.pop(), terminator) + + unittest.main() \ No newline at end of file