added stream.py, still need func to add to stream

This commit is contained in:
Kevin Froman 2020-04-29 01:41:29 -05:00
parent cafa4e6d11
commit 0dd9c1e9ac
6 changed files with 106 additions and 31 deletions

View File

@ -54,3 +54,12 @@ That said, one should not rely on any software when the stakes are too high.
![](dummy.png)
# Limitations + Road map
This project will forever follow the KISS principle, but these two three will be addressed.
* Multi-byte character support (full utf-8 support)
* Tor bridge support
* Support non-anonymous hidden services. Mainly useful for certain development needs

View File

@ -16,6 +16,7 @@ setup(name='youandme',
scripts=['src/yam/yam.py'],
author_email='beardog@mailbox.org',
url='http://github.com/beardog108/youandme',
python_requires='>=3.7',
install_requires=[
'stem',
'PySocks'

View File

@ -6,6 +6,7 @@ from threading import Thread
import tempfile
import argparse
from string import printable
from base64 import b85decode, b85encode
import socks
from stem.control import Controller
@ -15,6 +16,7 @@ try:
except ModuleNotFoundError:
pass
from youandme.commands import terminator
from youandme.server import server
from youandme.client import client
@ -22,31 +24,37 @@ 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
# taken from (but modified) stackoverflow.com/a/2838309
# by stackoverflow.com/users/133374/albert
# ccy-by-sa-3 creativecommons.org/licenses/by-sa/3.0/
# changes from source: import moved to top of file, bind to localhost
# vulnerable to race condition
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1",0))
s.bind(("127.0.0.1", 0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
def connector(host, send_data, recv_data, address="", control_port=1337, socks_port=1338):
def connector(host, send_data, recv_data,
address="", control_port=1337, socks_port=1338):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('127.0.0.1', socks_port))
sock.close()
if result != 0:
try:
launch_tor(control_port=control_port, socks_port=socks_port)
except OSError:
with tempfile.TemporaryDirectory() as tmpdirname:
launch_tor(control_port=control_port, socks_port=socks_port, data_dir=tmpdirname)
launch_tor(control_port=control_port,
socks_port=socks_port, data_dir=tmpdirname)
if host:
with Controller.from_port(port=control_port) as controller:
controller.authenticate()
@ -62,7 +70,8 @@ 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, Connection)
server(0.01, controller, conn, send_data, recv_data,
Connection)
else:
if not address.endswith('.onion'):
address += '.onion'
@ -71,8 +80,10 @@ def connector(host, send_data, recv_data, address="", control_port=1337, socks_p
except socks.GeneralProxyError:
Connection.connected = False
def chat(mode, send_data, recv_data, alpha):
print("A notice will be shown when connection is established, but messages may be typed now.")
print("A notice will be shown when connection is established," +
"but messages may be typed now.")
display_buffer = []
if mode == 'host':
@ -83,27 +94,16 @@ def chat(mode, send_data, recv_data, alpha):
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:
while len(display_buffer) != 0:
char = display_buffer.pop(0)
if alpha and char not in printable:
continue
print("\033[1;33m" + char + "\033[0m", end="")
except IndexError:
pass
sleep(0.1)
for message in get_messages
Thread(target=display_new, daemon=True).start()
def make_message():
while True:
new = input("\033[0m").encode('utf-8')
new = input("\033[0m").encode('utf-8') # nosec
for b in new:
send_data.append(b)
send_data.append(ord(b"\n"))
Thread(target=make_message, daemon=True).start()
while True:
try:
@ -113,15 +113,25 @@ def chat(mode, send_data, recv_data, alpha):
sleep(1)
except KeyboardInterrupt:
break
PORT_MESSAGE = "Specify any free ports above 1023"
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='End-to-end encrypted instant messaging with metadata privacy and perfect forward secrecy')
parser = argparse.ArgumentParser(
description='End-to-end encrypted messaging with metadata privacy')
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='')
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 stdout en-us typical characters',
default=False, type=bool)
parser.add_argument('--address',
help='Address to connect to. No port.', default='')
args = parser.parse_args()
if args.socks_port == 0: args.socks_port = _get_open_port()
@ -130,16 +140,17 @@ if __name__ == "__main__":
recv_data = bytearray()
if args.connection == 'conn':
if not args.address:
print("Must specify address if connecting (--address)", file=sys.stderr)
print("Must specify address if connecting (--address)",
file=sys.stderr)
sys.exit(3)
Thread(target=connector,
args=[False, send_data, recv_data],
kwargs={'address': args.address,
'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, 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()
'control_port': args.control_port}, daemon=True).start()
chat('host', send_data, recv_data, args.alphanum_only)

View File

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

19
src/youandme/stream.py Normal file
View File

@ -0,0 +1,19 @@
from base64 import b85encode, b85decode
from time import sleep
from youandme.commands import terminator
_b85alphabet = (b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
b"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~")
def decoded_recv_stream(raw_stream: bytearray, delay_seconds: int, max_buffer_size=) -> bytes:
while True:
for byte in raw_stream:
if byte == terminator:
yield b85decode(raw_stream[:len(raw_stream) - 1])
raw_stream.clear()
continue
if byte not in _b85alphabet:
raise ValueError('Not valid base85 encoding')
sleep(delay_seconds)

34
tests/test_stream.py Normal file
View File

@ -0,0 +1,34 @@
import unittest
import socket
from threading import Thread
import sys
import time
from base64 import b85decode, b85encode
from stem.control import Controller
from youandme import stream
from youandme.commands import terminator
def add_encoded_to_bytes_array_valid(message, array: bytearray):
for m in b85encode(message.encode('utf-8')):
array.append(m)
array.append(terminator)
class TestStream(unittest.TestCase):
def test_stream_get(self):
send_data = bytearray()
recv_data = bytearray()
data = "hello world"
#stream.decoded_recv_stream(recv_data, data)
add_encoded_to_bytes_array_valid(data, recv_data)
c = 0
for message in stream.decoded_recv_stream(recv_data, 1):
self.assertEqual(message.decode('utf-8'), data)
break
unittest.main()