From f6f526aad1280dcf5a1c7869a90e75dafa56152c Mon Sep 17 00:00:00 2001 From: quadrismegistus Date: Mon, 17 Aug 2020 17:23:40 +0100 Subject: [PATCH] =?UTF-8?q?p2p=20login=20working=20=F0=9F=98=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/main.py | 67 ++++++++++-------- client/p2p/api.py | 128 +++++++++++++++++++++++++++++++--- client/p2p/crypto.py | 29 ++++---- client/p2p/p2p.py | 19 +++-- client/root.kv | 20 +----- client/screens/login/login.kv | 5 +- client/screens/login/login.py | 6 +- client/screens/post/post.kv | 8 +-- client/screens/post/post.py | 48 ++++--------- client/watcher.py | 3 +- requirements.txt | 49 +++---------- 11 files changed, 218 insertions(+), 164 deletions(-) diff --git a/client/main.py b/client/main.py index 739b75b..933d52f 100644 --- a/client/main.py +++ b/client/main.py @@ -40,11 +40,22 @@ from p2p import p2p,crypto,api Window.size = WINDOW_SIZE -def log(*args): - with open('log.txt','a+') as of: - of.write(' '.join([str(x) for x in args])+'\n') +# with open('log.txt','w') as of: +# of.write('### LOG ###\n') +import logging +handler = logging.StreamHandler() +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +handler.setFormatter(formatter) +logger = logging.getLogger('app') +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) +def log(*args): + #with open('log.txt','a+') as of: + # of.write(' '.join([str(x) for x in args])+'\n') + line = ' '.join(str(x) for x in args) + logger.debug(line) class MyLayout(MDBoxLayout): scr_mngr = ObjectProperty(None) @@ -130,14 +141,19 @@ class MainApp(MDApp): # self.texture.wrap = 'clamp_to_edge' # self.texture.uvsize = (-2, -2) + with open('log.txt','w') as of: of.write('## LOG ##\n') + self.load_store() + # self.boot_kad() + from p2p.api import Api + self.api = Api(app_storage=self.store) self.username='' # bind global app,root app = self #self.username = self.store.get('userd').get('username') - self.load_store() + self.root = root = Builder.load_file('root.kv') draw_background(self.root) @@ -159,7 +175,7 @@ class MainApp(MDApp): if not self.is_logged_in(): self.root.change_screen('login') - log(self.username) + #log(self.username) else: # self.root.post_id=190 self.root.change_screen(DEFAULT_SCREEN) @@ -202,35 +218,23 @@ class MainApp(MDApp): def login(self,un=None,pw=None): - url = self.api+'/login' - - with self.get_session() as sess: - #res = requests.post(url, json={'name':un, 'passkey':pw}) - res = sess.post(url, json={'name':un, 'passkey':pw}) - log(res.text) - - if res.status_code==200: - data=res.json() - self.save_login(un) - return True - else: - # self.root.ids.login_status.text=res.text - return False + dat = self.api.login(un,pw) + log(dat) + if 'success' in dat: + self.save_login(un) + elif 'error' in dat: + self.root.ids.login_screen.login_status.text=dat['error'] + return False def register(self,un,pw): - # url = self.api+'/register' - - # with self.get_session() as sess: - # #res = requests.post(url, json={'name':un, 'passkey':pw}) - # res = sess.post(url, json={'name':un, 'passkey':pw}) - # if res.status_code==200: - # self.save_login(un) - # else: - # pass - # #self.root.ids.login_status.text=res.text - res = api.register(un,pw) + dat = self.api.register(un,pw) + if 'success' in dat: + self.save_login(un) + return True + elif 'error' in dat: + self.root.ids.login_screen.login_status.text=dat['error'] + return False - def upload(self,orig_img_src): url_upload=self.api+'/upload' filename=orig_img_src[0] if orig_img_src and os.path.exists(orig_img_src[0]) else '' @@ -303,6 +307,7 @@ class MainApp(MDApp): return jsond def get_posts(self): + return [] with self.get_session() as sess: with sess.get(self.api+'/posts') as r: log(r.text) diff --git a/client/p2p/api.py b/client/p2p/api.py index 45f8fe4..56a556d 100644 --- a/client/p2p/api.py +++ b/client/p2p/api.py @@ -10,8 +10,10 @@ import os,time from pathlib import Path from flask_api import status -from .p2p import connect import asyncio +from .crypto import * +from main import log +from .p2p import * # works better with tor? import json @@ -22,10 +24,125 @@ jsonify = json.dumps DEBUG = True UPLOAD_DIR = 'uploads/' ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} +NODES_PRIME = [("128.232.229.63",8468), ("68.66.241.111",8468)] +PORT_LISTEN = 8469 # Api Functions -NODE = connect() +class Api(object): + + + def __init__(self,app_storage): + #self.connect() + self.app_storage = app_storage + pass + + # def connect(self): + #from .p2p import connect + #self.node = connect() + + def get(self,key): + async def _get(): + node = Server(storage=HalfForgetfulStorage()) + await node.listen(PORT_LISTEN) + await node.bootstrap(NODES_PRIME) + return await node.get(key) + return asyncio.run(_get()) + + def set(self,key,value): + async def _set(): + node = Server(storage=HalfForgetfulStorage()) + await node.listen(PORT_LISTEN) + await node.bootstrap(NODES_PRIME) + return await node.set(key,value) + return asyncio.run(_set()) + + def has(self,key): + return self.get(key) is not None + + + ## PERSONS + def get_person(self,username): + person = self.get('/person/'+username) + return None if person is None else json.loads(person) + + def set_person(self,username,public_key): + pem_public_key = save_public_key(public_key,return_instead=True) + obj = {'name':username, 'public_key':pem_public_key.decode()} + obj_str = jsonify(obj) + self.set('/person/'+username,obj_str) + + + + + + ## Register + def register(self,name,passkey): + + if not (name and passkey): + error('name and passkey not set') + return {'error':'Register failed'},status.HTTP_400_BAD_REQUEST + + person = self.get_person(name) + if person is not None: + log('error! person exists') + return {'error':'Register failed'} + + private_key,public_key = new_keys(password=passkey,save=False) + pem_private_key = save_private_key(private_key,password=passkey,return_instead=True) + pem_public_key = save_public_key(public_key,return_instead=True) + + self.app_storage.put('_keys', + private=str(pem_private_key.decode()), + public=str(pem_public_key.decode())) #(private_key,password=passkey) + self.set_person(name,public_key) + + + log('success! Account created') + return {'success':'Account created', 'username':name} + + def load_private_key(self,password): + if not self.app_storage.exists('_keys'): return None + pem_private_key=self.app_storage.get('_keys').get('private') + try: + return load_private_key(pem_private_key.encode(),password) + except ValueError as e: + log('!!',e) + return None + + + + ## LOGIN + def login(self,name,passkey): + # verify input + if not (name and passkey): + return {'error':'Name and password required'} + + # try to load private key + private_key = self.load_private_key(passkey) + if private_key is None: + return {'error':'You have never registered on this device'} + + # see if user exists + person = self.get_person(name) + log(person) + if person is None: + return {'error':'Login failed'} + + # verify keys + person_public_key_pem = person['public_key'] + public_key = load_public_key(person_public_key_pem) + real_public_key = private_key.public_key() + + #log('PUBLIC',public_key.public_numbers()) + #log('REAL PUBLIC',real_public_key.public_numbers()) + + if public_key.public_numbers() != real_public_key.public_numbers(): + return {'error':'keys do not match!'} + return {'success':'Login successful', 'username':name} + + +""" ## LOGIN @@ -45,11 +162,6 @@ def login(data): return {'success':'Login success'},status.HTTP_200_OK -def get_person(username): - async def go(): - return await NODE.get('/person/'+username) - - return asyncio.run(run()) def register(name,passkey): @@ -73,8 +185,6 @@ def register(name,passkey): -""" - ## CREATE def allowed_file(filename): diff --git a/client/p2p/crypto.py b/client/p2p/crypto.py index aa2b617..6a01dd4 100644 --- a/client/p2p/crypto.py +++ b/client/p2p/crypto.py @@ -27,7 +27,7 @@ def new_keys(save=True,password=None): return private_key,public_key -def save_private_key(private_key,fn=PATH_PRIVATE_KEY,return_instead=False): +def save_private_key(private_key,fn=PATH_PRIVATE_KEY,password=None, return_instead=False): pem = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, @@ -48,23 +48,28 @@ def save_public_key(public_key,fn=PATH_PUBLIC_KEY,return_instead=False): ### LOADING KEYS def load_keys(): - return (load_private_key(), load_public_key()) + return (load_private_key_from_file(), load_public_key_from_file()) -def load_private_key(fn=PATH_PRIVATE_KEY,password=None): +def load_private_key(pem,password=None): + return serialization.load_pem_private_key( + pem, + password=password.encode() if password else None, + backend=default_backend() + ) + +def load_private_key_from_file(fn=PATH_PRIVATE_KEY,password=None): with open(fn, "rb") as key_file: - return serialization.load_pem_private_key( - key_file.read(), - password=password.encode(), + return load_private_key(key_file.read(), password) + +def load_public_key(pem): + return serialization.load_pem_public_key( + pem, backend=default_backend() ) - -def load_public_key(fn=PATH_PUBLIC_KEY): +def load_public_key_from_file(fn=PATH_PUBLIC_KEY): with open(fn, "rb") as key_file: - return serialization.load_pem_public_key( - key_file.read(), - backend=default_backend() - ) + return load_public_key(key_file.read()) ### DE/ENCRYPTING def encrypt_msg(message, public_key): diff --git a/client/p2p/p2p.py b/client/p2p/p2p.py index 6eafb75..ca09d0c 100644 --- a/client/p2p/p2p.py +++ b/client/p2p/p2p.py @@ -33,9 +33,12 @@ class HalfForgetfulStorage(ForgetfulStorage): self.data[key] = (time.monotonic(), value) self.write() + def set(key,value): + self[key]=value + def write(self): with open(self.fn,'wb') as f: - pickle.dump(self.data, f, protocol=pickle.HIGHEST_PROTOCOL) + pickle.dump(self.data, f) def get(self, key, default=None): # self.cull() @@ -49,14 +52,16 @@ class HalfForgetfulStorage(ForgetfulStorage): return self.data[key][1] -handler = logging.StreamHandler() -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') -handler.setFormatter(formatter) -log = logging.getLogger('kademlia') -log.addHandler(handler) -log.setLevel(logging.DEBUG) + def start_first_node(): + handler = logging.StreamHandler() + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setFormatter(formatter) + log = logging.getLogger('kademlia') + log.addHandler(handler) + log.setLevel(logging.DEBUG) + loop = asyncio.get_event_loop() loop.set_debug(True) diff --git a/client/root.kv b/client/root.kv index 99997f8..0b76970 100644 --- a/client/root.kv +++ b/client/root.kv @@ -43,19 +43,6 @@ size_hint:1,None - - -: - name: 'post' - id: post_screen - - -: - name: 'view' - - - - ### LAYOUT @@ -103,12 +90,9 @@ MyLayout: FeedScreen: id: feed_screen - AddPostScreen: - id: add_post_screen + PostScreen: + id: post_screen - ViewPostScreen: - id: view_post_screen - MessagesScreen: id: messages_screen diff --git a/client/screens/login/login.kv b/client/screens/login/login.kv index 01e3f88..1fc07e9 100644 --- a/client/screens/login/login.kv +++ b/client/screens/login/login.kv @@ -26,11 +26,12 @@ required: True write_tab: False multiline: False - helper_text_mode: "on_error" + helper_text_mode: "persistent" color_mode: 'custom' line_color_focus: 1,0,0,1 line_color_normal: 1,0,0,1 current_hint_text_color: 1,0,0,1 + error_color:1,0,0,1 # pos_hint: {'x':1,'y':0.8} # size_hint:(None,None) @@ -43,7 +44,7 @@ required: True write_tab: False multiline: False - helper_text_mode: "on_error" + helper_text_mode: "persistent" color_mode: 'custom' line_color_focus: 1,0,0,1 line_color_normal: 1,0,0,1 diff --git a/client/screens/login/login.py b/client/screens/login/login.py index a3a89a8..3c954d3 100644 --- a/client/screens/login/login.py +++ b/client/screens/login/login.py @@ -19,14 +19,14 @@ class LoginScreen(BaseScreen): # if app.is_logged_in(): # app.root.change_screen('feed') def on_pre_enter(self): - log(self.ids) - log('hello?') + #log(self.ids) + #log('hello?') self.layout = LoginBoxLayout() self.username_field = UsernameField() self.username_field.line_color_focus=(1,0,0,1) self.layout.add_widget(self.username_field) - log(self.username_field) + #log(self.username_field) # self.username_field.text='hello????' self.password_field = PasswordField() diff --git a/client/screens/post/post.kv b/client/screens/post/post.kv index 1c9f026..a7a68f8 100644 --- a/client/screens/post/post.kv +++ b/client/screens/post/post.kv @@ -1,4 +1,4 @@ - +#:import PostScreen screens.post.post.PostScreen id: post_content_input @@ -151,10 +151,6 @@ -: +: name: 'post' id: post_screen - - -: - name: 'view' diff --git a/client/screens/post/post.py b/client/screens/post/post.py index 9b248ba..38385fe 100644 --- a/client/screens/post/post.py +++ b/client/screens/post/post.py @@ -10,33 +10,11 @@ from main import log from screens.feed.feed import * import os,time,threading from threading import Thread - - from kivymd.uix.dialog import MDDialog -# # Progress bar code -# class ProgressPopup(MDDialog): -# def __init__(self, *args, **kwargs): -# super().__init__(*args, **kwargs) -# content = MDLabel(font_style='Body1', -# theme_text_color='Secondary', -# text=kwargs.get('text',''), -# size_hint_y=None, -# valign='top') -# content.bind(texture_size=content.setter('size')) -# self.dialog = MDDialog(title="Close", -# content=content, -# size_hint=(.3, None), -# height='200dp') - -# self.dialog.add_action_button("Close me!", -# action=lambda *x: self.dismiss_callback()) -# self.dialog.open() - class ProgressPopup(MDDialog): pass class MessagePopup(MDDialog): pass - class UploadButton(MDRectangleFlatButton): ''' Button that triggers 'filechooser.open_file()' and processes @@ -73,7 +51,7 @@ class PostButton(MDRectangleFlatButton): pass class PostStatus(MDRectangleFlatButton): pass -class AddPostScreen(ProtectedScreen): +class PostScreen(ProtectedScreen): post_id = ObjectProperty() def on_pre_enter(self): @@ -200,20 +178,20 @@ class AddPostScreen(ProtectedScreen): Thread(target=do_post).start() -class ViewPostScreen(ProtectedScreen): - post_id = ObjectProperty() +# class ViewPostScreen(ProtectedScreen): +# post_id = ObjectProperty() - def on_pre_enter(self): - for child in self.children: - log('child: '+str(child)) - self.remove_widget(child) +# def on_pre_enter(self): +# for child in self.children: +# log('child: '+str(child)) +# self.remove_widget(child) - post_json = self.app.get_post(self.root.post_id) - post = PostCard(post_json) - self.add_widget(post) +# post_json = self.app.get_post(self.root.post_id) +# post = PostCard(post_json) +# self.add_widget(post) - def on_enter(self): - for child in self.children: child.load_image() +# def on_enter(self): +# for child in self.children: child.load_image() - pass +# pass diff --git a/client/watcher.py b/client/watcher.py index f2de54e..7a283cf 100644 --- a/client/watcher.py +++ b/client/watcher.py @@ -38,7 +38,8 @@ class Handler(FileSystemEventHandler): def on_any_event(event): if '/cache/' in str(event.src_path): return None if '__pycache__' in str(event.src_path): return None - + if 'sto.dat' in str(event.src_path): return None + if event.is_directory: return None diff --git a/requirements.txt b/requirements.txt index 65f553c..e1e227a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,69 +1,38 @@ astroid==2.4.2 -attrs==19.3.0 -Automat==20.2.0 certifi==2020.6.20 -characteristic==14.3.0 +cffi==1.14.2 chardet==3.0.4 -Click==7.0 -colorama==0.4.3 -constantly==15.1.0 -dnspython==1.16.0 +click==7.1.2 +cryptography==3.0 docutils==0.16 -eventlet==0.26.1 Flask==1.1.2 Flask-API==2.0 -Flask-SocketIO==4.3.1 -Flask-Sockets==0.2.1 -Flask-Twisted==0.1.2 -gevent==20.6.2 -gevent-websocket==0.10.1 -greenlet==0.4.16 -gunicorn==20.0.4 -hyperlink==20.0.1 idna==2.10 -incremental==17.5.0 isort==4.3.21 itsdangerous==1.1.0 Jinja2==2.11.2 +kademlia==2.2.1 Kivy==1.11.1 Kivy-Garden==0.1.4 kivymd==0.104.1 -klein==20.6.0 lazy-object-proxy==1.4.3 llp==0.2.2 MarkupSafe==1.1.1 mccabe==0.6.1 -monotonic==1.5 mpi-slingshot==0.2.0 -neo4j-driver==1.7.2 -neobolt==1.7.17 -neomodel==3.3.2 -neotime==1.7.4 -observable==1.0.3 pathtools==0.1.2 Pillow==7.2.0 plyer==1.4.3 -prompt-toolkit==2.0.10 -py2neo==4.3.0 -Pygments==2.3.1 -PyHamcrest==2.0.2 +pycparser==2.20 +Pygments==2.6.1 pylint==2.5.3 -PySocks==1.7.1 -python-dotenv==0.14.0 -python-engineio==3.13.1 -python-socketio==4.6.0 -pytz==2020.1 requests==2.24.0 -requests-futures==1.0.0 +rpcudp==4.0.1 six==1.15.0 toml==0.10.1 -Tubes==0.2.0 -Twisted==20.3.0 typed-ast==1.4.1 -urllib3==1.24.3 +u-msgpack-python==2.7.0 +urllib3==1.25.10 watchdog==0.10.3 -wcwidth==0.2.5 Werkzeug==1.0.1 wrapt==1.12.1 -zope.event==4.4 -zope.interface==5.1.0