added connection loss detection, strict printable character filter support

This commit is contained in:
Kevin Froman 2020-04-23 22:18:29 -05:00
parent e47173b586
commit 0173f136fb
6 changed files with 56 additions and 22 deletions

View File

@ -2,6 +2,17 @@
This project uses Semantic Versioning 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 ## 1.0.0
Made yam a proper script (install and you can run from path with $ yam.py <args>) Made yam a proper script (install and you can run from path with $ yam.py <args>)

View File

@ -7,7 +7,7 @@ with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
packages = find_packages(exclude=['contrib', 'docs', 'tests']) packages = find_packages(exclude=['contrib', 'docs', 'tests'])
setup(name='youandme', setup(name='youandme',
version='1.0.0', version='1.1.1',
description='Simple private data sharing via bytearrays, Tor tunneling and metadata paranoia', description='Simple private data sharing via bytearrays, Tor tunneling and metadata paranoia',
long_description=long_description, long_description=long_description,
long_description_content_type='text/markdown', long_description_content_type='text/markdown',
@ -15,7 +15,7 @@ setup(name='youandme',
packages=packages, packages=packages,
scripts=['src/yam/yam.py'], scripts=['src/yam/yam.py'],
author_email='beardog@mailbox.org', author_email='beardog@mailbox.org',
url='https://chaoswebs.net', url='http://github.com/beardog108/youandme',
install_requires=[ install_requires=[
'stem', 'stem',
'PySocks' 'PySocks'

View File

@ -1,11 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys import sys
import socket import socket
from time import time, sleep from time import sleep
from threading import Thread from threading import Thread
import tempfile import tempfile
import argparse import argparse
from string import printable
import socks
from stem.control import Controller from stem.control import Controller
try: try:
@ -16,9 +18,15 @@ except ModuleNotFoundError:
from youandme.server import server from youandme.server import server
from youandme.client import client from youandme.client import client
class Connection:
connected = True
class _Address: class _Address:
address = "" address = ""
def _get_open_port(): 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/ # 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 # 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 _Address.address = serv.service_id
conn, addr = s.accept() conn, addr = s.accept()
server(0.01, controller, conn, send_data, recv_data) server(0.01, controller, conn, send_data, recv_data, Connection)
else: else:
if not address.endswith('.onion'): if not address.endswith('.onion'):
address += '.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, alpha):
def chat(mode, send_data, recv_data): print("A notice will be shown when connection is established, but messages may be typed now.")
display_buffer = [] display_buffer = []
if mode == 'host': if mode == 'host':
print('Creating tunnel...')
while _Address.address == "": while _Address.address == "":
sleep(0.01) sleep(0.01)
print('Tunnel address:')
print(_Address.address) print(_Address.address)
def display_new(): def display_new():
while True: while True:
try: try:
char = chr(recv_data.pop(0)) char = chr(recv_data.pop(0))
display_buffer.append(char) display_buffer.append(char)
if char == "\n" or char == "\r\n" or len(display_buffer) > 100: 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: while len(display_buffer) != 0:
#print("\033[1;33m", display_buffer.pop(0), "\033[0m", end='') char = display_buffer.pop(0)
print("\033[1;33m" + display_buffer.pop(0) + "\033[0m", end="") 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: except IndexError:
pass pass
@ -91,8 +108,8 @@ def chat(mode, send_data, recv_data):
Thread(target=make_message, daemon=True).start() Thread(target=make_message, daemon=True).start()
while True: while True:
try: try:
if send_data is None: if not Connection.connected:
print("Well crap, we lost connection.") print("Cease dancing ☹️")
break break
sleep(1) sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
@ -100,10 +117,11 @@ def chat(mode, send_data, recv_data):
PORT_MESSAGE = "Specify any free ports above 1023" PORT_MESSAGE = "Specify any free ports above 1023"
if __name__ == "__main__": 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('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('--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('--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='') parser.add_argument('--address', help='Address to connect to. No port.', default='')
args = parser.parse_args() args = parser.parse_args()
@ -120,9 +138,9 @@ if __name__ == "__main__":
kwargs={'address': args.address, kwargs={'address': args.address,
'socks_port': args.socks_port, 'socks_port': args.socks_port,
'control_port': args.control_port}, daemon=True).start() 'control_port': args.control_port}, daemon=True).start()
chat('conn', send_data, recv_data) chat('conn', send_data, recv_data, args.alphanum_only)
else: else:
Thread(target=connector, args=[True, send_data, recv_data], Thread(target=connector, args=[True, send_data, recv_data],
kwargs={'socks_port': args.socks_port, kwargs={'socks_port': args.socks_port,
'control_port': args.control_port}, daemon=True).start() 'control_port': args.control_port}, daemon=True).start()
chat('host', send_data, recv_data) chat('host', send_data, recv_data, args.alphanum_only)

View File

@ -4,14 +4,17 @@ from time import sleep
import socks import socks
from .commands import garbage_character 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 = socks.socksocket() # Same API as socket.socket in the standard lib
s.set_proxy(socks.SOCKS5, "127.0.0.1", socks_port, rdns=True) s.set_proxy(socks.SOCKS5, "127.0.0.1", socks_port, rdns=True)
def send_loop(): def send_loop():
for i in WELCOME_MESSAGE:
send_data.append(ord(i))
while True: while True:
to_send = None to_send = None
if send_data: 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) s.send(to_send)
except BrokenPipeError: except BrokenPipeError:
# lost connection # lost connection
pass connection.connected = False
except BrokenPipeError: except BrokenPipeError:
pass connection.connected = False
sleep(delay) sleep(delay)
# Can be treated identical to a regular socket object # Can be treated identical to a regular socket object

View File

@ -1 +1,2 @@
garbage_character = b'\x00' garbage_character = b'\x00'
WELCOME_MESSAGE = "Connection established. Dance like no one is watching :)\n"

View File

@ -1,11 +1,12 @@
import socket import socket
import time import time
from.commands import garbage_character from.commands import garbage_character
from.commands import WELCOME_MESSAGE
from threading import Thread 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(): def send_loop():
while True: while True:
time.sleep(delay) time.sleep(delay)
@ -22,15 +23,15 @@ def server(delay: int, controller, conn, send_data: bytearray, recv_data: bytear
except TypeError: except TypeError:
conn.sendall(chr(char).encode('utf-8')) conn.sendall(chr(char).encode('utf-8'))
except OSError: except OSError:
pass connection.connected = False
first_rec = True first_rec = True
WELCOME_MESSAGE = "Connection established\n"
with conn: with conn:
Thread(target=send_loop, daemon=True).start() Thread(target=send_loop, daemon=True).start()
while True: while True:
try: try:
data = conn.recv(1) data = conn.recv(1)
except ConnectionResetError: except ConnectionResetError:
connection.connected = False
break break
if not data: break if not data: break
if first_rec: if first_rec: