added stream.py, still need func to add to stream
This commit is contained in:
parent
cafa4e6d11
commit
0dd9c1e9ac
@ -54,3 +54,12 @@ That said, one should not rely on any software when the stakes are too high.
|
|||||||
|
|
||||||
|
|
||||||
![](dummy.png)
|
![](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
|
||||||
|
1
setup.py
1
setup.py
@ -16,6 +16,7 @@ setup(name='youandme',
|
|||||||
scripts=['src/yam/yam.py'],
|
scripts=['src/yam/yam.py'],
|
||||||
author_email='beardog@mailbox.org',
|
author_email='beardog@mailbox.org',
|
||||||
url='http://github.com/beardog108/youandme',
|
url='http://github.com/beardog108/youandme',
|
||||||
|
python_requires='>=3.7',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'stem',
|
'stem',
|
||||||
'PySocks'
|
'PySocks'
|
||||||
|
@ -6,6 +6,7 @@ from threading import Thread
|
|||||||
import tempfile
|
import tempfile
|
||||||
import argparse
|
import argparse
|
||||||
from string import printable
|
from string import printable
|
||||||
|
from base64 import b85decode, b85encode
|
||||||
|
|
||||||
import socks
|
import socks
|
||||||
from stem.control import Controller
|
from stem.control import Controller
|
||||||
@ -15,6 +16,7 @@ try:
|
|||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
from youandme.commands import terminator
|
||||||
from youandme.server import server
|
from youandme.server import server
|
||||||
from youandme.client import client
|
from youandme.client import client
|
||||||
|
|
||||||
@ -22,14 +24,16 @@ from youandme.client import client
|
|||||||
class Connection:
|
class Connection:
|
||||||
connected = True
|
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) stackoverflow.com/a/2838309
|
||||||
# changes from source: import moved to top of file, bind specifically to localhost
|
# 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
|
# vulnerable to race condition
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
s.bind(("127.0.0.1", 0))
|
s.bind(("127.0.0.1", 0))
|
||||||
@ -38,15 +42,19 @@ def _get_open_port():
|
|||||||
s.close()
|
s.close()
|
||||||
return port
|
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)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
result = sock.connect_ex(('127.0.0.1', socks_port))
|
result = sock.connect_ex(('127.0.0.1', socks_port))
|
||||||
|
sock.close()
|
||||||
if result != 0:
|
if result != 0:
|
||||||
try:
|
try:
|
||||||
launch_tor(control_port=control_port, socks_port=socks_port)
|
launch_tor(control_port=control_port, socks_port=socks_port)
|
||||||
except OSError:
|
except OSError:
|
||||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
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:
|
if host:
|
||||||
with Controller.from_port(port=control_port) as controller:
|
with Controller.from_port(port=control_port) as controller:
|
||||||
controller.authenticate()
|
controller.authenticate()
|
||||||
@ -62,7 +70,8 @@ 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, Connection)
|
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'
|
||||||
@ -71,8 +80,10 @@ def connector(host, send_data, recv_data, address="", control_port=1337, socks_p
|
|||||||
except socks.GeneralProxyError:
|
except socks.GeneralProxyError:
|
||||||
Connection.connected = False
|
Connection.connected = False
|
||||||
|
|
||||||
|
|
||||||
def chat(mode, send_data, recv_data, alpha):
|
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 = []
|
display_buffer = []
|
||||||
|
|
||||||
if mode == 'host':
|
if mode == 'host':
|
||||||
@ -83,27 +94,16 @@ def chat(mode, send_data, recv_data, alpha):
|
|||||||
print(_Address.address)
|
print(_Address.address)
|
||||||
|
|
||||||
def display_new():
|
def display_new():
|
||||||
while True:
|
for message in get_messages
|
||||||
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)
|
|
||||||
Thread(target=display_new, daemon=True).start()
|
Thread(target=display_new, daemon=True).start()
|
||||||
|
|
||||||
def make_message():
|
def make_message():
|
||||||
while True:
|
while True:
|
||||||
new = input("\033[0m").encode('utf-8')
|
new = input("\033[0m").encode('utf-8') # nosec
|
||||||
for b in new:
|
for b in new:
|
||||||
send_data.append(b)
|
send_data.append(b)
|
||||||
send_data.append(ord(b"\n"))
|
send_data.append(ord(b"\n"))
|
||||||
|
|
||||||
Thread(target=make_message, daemon=True).start()
|
Thread(target=make_message, daemon=True).start()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -113,15 +113,25 @@ def chat(mode, send_data, recv_data, alpha):
|
|||||||
sleep(1)
|
sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
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 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('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',
|
||||||
parser.add_argument('--control-port', help='Tor control port (will use random if not given)', default=0, type=int)
|
help='Socks proxy port (will use random if not given)',
|
||||||
parser.add_argument('--alphanum-only', help='Only allow english alpha-numeric characters and spaces/tabs/new lines', default=False, type=bool)
|
default=0, type=int)
|
||||||
parser.add_argument('--address', help='Address to connect to. No port.', default='')
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.socks_port == 0: args.socks_port = _get_open_port()
|
if args.socks_port == 0: args.socks_port = _get_open_port()
|
||||||
@ -130,7 +140,8 @@ if __name__ == "__main__":
|
|||||||
recv_data = bytearray()
|
recv_data = bytearray()
|
||||||
if args.connection == 'conn':
|
if args.connection == 'conn':
|
||||||
if not args.address:
|
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)
|
sys.exit(3)
|
||||||
Thread(target=connector,
|
Thread(target=connector,
|
||||||
args=[False, send_data, recv_data],
|
args=[False, send_data, recv_data],
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
garbage_character = b'\x00'
|
garbage_character = b'\x00'
|
||||||
|
terminator = 1
|
||||||
WELCOME_MESSAGE = "Connection established. Dance like no one is watching :)\n"
|
WELCOME_MESSAGE = "Connection established. Dance like no one is watching :)\n"
|
19
src/youandme/stream.py
Normal file
19
src/youandme/stream.py
Normal 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
34
tests/test_stream.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user