From 0173f136fba8341320d8b0a1ee88142adbd5f8ff Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Thu, 23 Apr 2020 22:18:29 -0500 Subject: [PATCH] added connection loss detection, strict printable character filter support --- CHANGELOG.md | 11 ++++++++++ setup.py | 4 ++-- src/yam/yam.py | 44 ++++++++++++++++++++++++++++------------ src/youandme/client.py | 9 +++++--- src/youandme/commands.py | 3 ++- src/youandme/server.py | 7 ++++--- 6 files changed, 56 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a682631..093d668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ This project uses Semantic Versioning + +## 1.1.1 + +Fixed setup.py project URL + + +## 1.1.0 + +Added detection of connection loss +Added --alphanum-only argument + ## 1.0.0 Made yam a proper script (install and you can run from path with $ yam.py ) diff --git a/setup.py b/setup.py index 3e61b23..4818363 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.0.0', + version='1.1.1', description='Simple private data sharing via bytearrays, Tor tunneling and metadata paranoia', long_description=long_description, long_description_content_type='text/markdown', @@ -15,7 +15,7 @@ setup(name='youandme', packages=packages, scripts=['src/yam/yam.py'], author_email='beardog@mailbox.org', - url='https://chaoswebs.net', + url='http://github.com/beardog108/youandme', install_requires=[ 'stem', 'PySocks' diff --git a/src/yam/yam.py b/src/yam/yam.py index 3a72354..74f9faf 100644 --- a/src/yam/yam.py +++ b/src/yam/yam.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 import sys import socket -from time import time, sleep +from time import sleep from threading import Thread import tempfile import argparse +from string import printable +import socks from stem.control import Controller try: @@ -16,9 +18,15 @@ except ModuleNotFoundError: from youandme.server import server from youandme.client import client + +class Connection: + connected = True + class _Address: address = "" + + def _get_open_port(): # taken from (but modified) https://stackoverflow.com/a/2838309 by https://stackoverflow.com/users/133374/albert ccy-by-sa-3 https://creativecommons.org/licenses/by-sa/3.0/ # changes from source: import moved to top of file, bind specifically to localhost @@ -54,29 +62,38 @@ def connector(host, send_data, recv_data, address="", control_port=1337, socks_p ) _Address.address = serv.service_id conn, addr = s.accept() - server(0.01, controller, conn, send_data, recv_data) + server(0.01, controller, conn, send_data, recv_data, Connection) else: if not address.endswith('.onion'): address += '.onion' - client(0.01, address, socks_port, send_data, recv_data) + try: + client(0.01, address, socks_port, send_data, recv_data, Connection) + except socks.GeneralProxyError: + Connection.connected = False - -def chat(mode, send_data, recv_data): +def chat(mode, send_data, recv_data, alpha): + print("A notice will be shown when connection is established, but messages may be typed now.") display_buffer = [] + if mode == 'host': + print('Creating tunnel...') while _Address.address == "": sleep(0.01) + print('Tunnel address:') print(_Address.address) + def display_new(): while True: try: char = chr(recv_data.pop(0)) display_buffer.append(char) if char == "\n" or char == "\r\n" or len(display_buffer) > 100: - #print("\033[1;33m", char, "\033[0m", end="\n") while len(display_buffer) != 0: - #print("\033[1;33m", display_buffer.pop(0), "\033[0m", end='') - print("\033[1;33m" + display_buffer.pop(0) + "\033[0m", end="") + char = display_buffer.pop(0) + if alpha and char not in printable and \ + char not in ('\n', '\r', ' ', '\t'): + continue + print("\033[1;33m" + char + "\033[0m", end="") except IndexError: pass @@ -91,8 +108,8 @@ def chat(mode, send_data, recv_data): Thread(target=make_message, daemon=True).start() while True: try: - if send_data is None: - print("Well crap, we lost connection.") + if not Connection.connected: + print("Cease dancing ☹️") break sleep(1) except KeyboardInterrupt: @@ -100,10 +117,11 @@ def chat(mode, send_data, recv_data): PORT_MESSAGE = "Specify any free ports above 1023" if __name__ == "__main__": - parser = argparse.ArgumentParser(description='End-to-end encrpyted instant messaging with metadata privacy and perfect forward secrecy') + parser = argparse.ArgumentParser(description='End-to-end encrypted instant messaging with metadata privacy and perfect forward secrecy') parser.add_argument('connection', choices=['host', 'conn']) parser.add_argument('--socks-port', help='Socks proxy port (will use random if not given)', default=0, type=int) parser.add_argument('--control-port', help='Tor control port (will use random if not given)', default=0, type=int) + parser.add_argument('--alphanum-only', help='Only allow english alpha-numeric characters and spaces/tabs/new lines', default=False, type=bool) parser.add_argument('--address', help='Address to connect to. No port.', default='') args = parser.parse_args() @@ -120,9 +138,9 @@ if __name__ == "__main__": kwargs={'address': args.address, 'socks_port': args.socks_port, 'control_port': args.control_port}, daemon=True).start() - chat('conn', send_data, recv_data) + chat('conn', send_data, recv_data, args.alphanum_only) else: Thread(target=connector, args=[True, send_data, recv_data], kwargs={'socks_port': args.socks_port, 'control_port': args.control_port}, daemon=True).start() - chat('host', send_data, recv_data) \ No newline at end of file + chat('host', send_data, recv_data, args.alphanum_only) \ No newline at end of file diff --git a/src/youandme/client.py b/src/youandme/client.py index 2af14a4..693b83c 100644 --- a/src/youandme/client.py +++ b/src/youandme/client.py @@ -4,14 +4,17 @@ from time import sleep import socks from .commands import garbage_character +from .commands import WELCOME_MESSAGE -def client(delay: int, hs_id, socks_port, send_data: bytearray, recv_data: bytearray): +def client(delay: int, hs_id, socks_port, send_data: bytearray, recv_data: bytearray, connection: "Connection"): s = socks.socksocket() # Same API as socket.socket in the standard lib s.set_proxy(socks.SOCKS5, "127.0.0.1", socks_port, rdns=True) def send_loop(): + for i in WELCOME_MESSAGE: + send_data.append(ord(i)) while True: to_send = None if send_data: @@ -27,9 +30,9 @@ def client(delay: int, hs_id, socks_port, send_data: bytearray, recv_data: bytea s.send(to_send) except BrokenPipeError: # lost connection - pass + connection.connected = False except BrokenPipeError: - pass + connection.connected = False sleep(delay) # Can be treated identical to a regular socket object diff --git a/src/youandme/commands.py b/src/youandme/commands.py index f4e0dec..af458da 100644 --- a/src/youandme/commands.py +++ b/src/youandme/commands.py @@ -1 +1,2 @@ -garbage_character = b'\x00' \ No newline at end of file +garbage_character = b'\x00' +WELCOME_MESSAGE = "Connection established. Dance like no one is watching :)\n" \ No newline at end of file diff --git a/src/youandme/server.py b/src/youandme/server.py index 7d08c9c..2513d54 100644 --- a/src/youandme/server.py +++ b/src/youandme/server.py @@ -1,11 +1,12 @@ import socket import time from.commands import garbage_character +from.commands import WELCOME_MESSAGE from threading import Thread -def server(delay: int, controller, conn, send_data: bytearray, recv_data: bytearray): +def server(delay: int, controller, conn, send_data: bytearray, recv_data: bytearray, connection: "Connection"): def send_loop(): while True: time.sleep(delay) @@ -22,15 +23,15 @@ def server(delay: int, controller, conn, send_data: bytearray, recv_data: bytear except TypeError: conn.sendall(chr(char).encode('utf-8')) except OSError: - pass + connection.connected = False first_rec = True - WELCOME_MESSAGE = "Connection established\n" with conn: Thread(target=send_loop, daemon=True).start() while True: try: data = conn.recv(1) except ConnectionResetError: + connection.connected = False break if not data: break if first_rec: