import requests import urllib.parse from threading import Thread import os import ssl import socketio import logging, traceback import json import time from libs.app.common.paths import ROOT_DIR from libs.app.common.logging import get_logger from libs.app.common.network_utils import check_url from libs.app.common.process import new_python_process from libs.noSys.noSysModule import NoSysModule from libs.noSys.users import User from .lockboxService import UserData logger = get_logger() class LockboxClient(NoSysModule): def __init__(self, nosys_core): super().__init__(nosys_core) self.api_host = self.config.get("server").get("host") self.api_port = self.config.get("server").get("port") self.service_url = f'{self.api_host}:{self.api_port}' self.session = requests.Session() certs_path = os.path.join(ROOT_DIR, "libs", "api", "certs") ca_path = os.path.join(certs_path, "ca.pem") self.session.verify = ca_path session_socketio = requests.Session() session_socketio.verify = ca_path self.socketio = socketio.Client(http_session=session_socketio) self.sio_events() self.users = {} # UserData self.user_tokens = {} self.signature_requests = {} # request_id | callback def setup(self): self.nosys_core.modules.pmc = self def on_nosys_ready(self, event): logger.debug("LOCKBOX READY") self.starts_lockbox_service() self.connect() # TODO Remove it # self.add("I0x1Y2FzR2FicmllbFZhekRvc1NhbnRvc0luYWNpbyE=", UserData(proof_of_work="eYnU*@")) self.users = self.user_list() for user in self.users: u = User(user) self.nosys_core.users.add_user(u) def starts_lockbox_service(self): try: health_check_url = f"{self.service_url}/healthCheck" if not check_url(health_check_url, timeout=3): logger.debug(f"Starting lockbox Service in a new process") process_pid = new_python_process("libs/lockbox/lockboxService.py", args=[self.api_port], new_console=True) logger.debug(f"Lockbox process PID {process_pid}") else: logger.debug(f"Lockbox service already running in {health_check_url}") except Exception: logger.exception("ERROR") def add(self, password, data = UserData()): add_url = f"{self.service_url}/users" body = {'password': password, 'data':data.__dict__} result = self.session.post(add_url, json = body) content = result.json() user_token = content["token"] verifying_key = content["verifying_key"] # self.users[verifying_key] = data self.user_tokens[verifying_key] = user_token return (verifying_key, user_token) def user_list(self): users_list_url = f"{self.service_url}/users" result = self.session.get(users_list_url) for user in result.json(): print("LOGGED", user["logged"]) if user["logged"]: verifying_key = user["id"] self.users[verifying_key] = UserData(id=user["id"],proof_of_work=user["proof_of_work"], time_to_live=user["time_to_live"], added_at=user["added_at"], logged=user["logged"]) return self.users def set_authorization_header(self, user, headers={}): if user in self.user_tokens: headers["Authorization"] = f'Bearer {self.user_tokens[user]}' return headers def get(self, user): # users_data_url = f"{self.service_url}/users/{urllib.parse.quote(user, safe='')}" # headers = self.set_authorization_header(user) # result = self.session.get(users_data_url, headers=headers) # content = result.json() # data = UserData(proof_of_work=content["proof_of_work"]) data = self.users[user] return data def sign(self, data, user, callback, info=None): sign_url = f"{self.service_url}/users/{urllib.parse.quote(user, safe='')}/signatures" headers = self.set_authorization_header(user) body = {'data': data, "info":info} result = self.session.post(sign_url, json = body, headers=headers) request_id = result.json()["requestId"] self.signature_requests[request_id] = callback return request_id def connect(self): while True: try: logger.debug(f"Trying to connect to lockbox service {self.service_url}") self.socketio.connect(self.service_url, wait=True ,wait_timeout=60, transports=["websocket"]) logger.debug(f"Lockbox service connected {self.service_url}") break except Exception: logger.exception(f"Failed to connect to lockbox service {self.service_url} - Retrying in 10 seconds") time.sleep(10) # self.socketio.emit('message', {'from': 'client'}) def sio_events(self): @self.socketio.on('message') def message(*args, **kwargs): logger.debug("Message",args, kwargs) @self.socketio.on("userAdded") def on_user_added(*args, **kwargs): user_id = args[0] logger.debug(f"User added {user_id}") self.user_list() if user_id in self.users: u = User(user_id) self.nosys_core.users.add_user(u) @self.socketio.on("signatureWaiting") def on_signature_waiting(*args, **kwargs): logger.debug(f"Signature Waiting {args[0]}") @self.socketio.on("signatureResponse") def on_signature_response(*args, **kwargs): logger.debug(f"Signature response {args[0]}") request_id = args[0]["requestId"] signature = args[0]["signature"] if request_id in self.signature_requests: self.signature_requests[request_id](request_id, signature) # signature = result.json()["signature"] # if signature: # return signature # else: # raise Exception("Sign data failed")