progress removing onionr.py

master
Kevin Froman 2019-08-03 23:52:57 -05:00
parent a6fec9eefb
commit aea32bd1bc
21 changed files with 106 additions and 52 deletions

View File

@ -54,6 +54,7 @@ from utils import createdirs
createdirs.create_dirs() createdirs.create_dirs()
from onionrcommands import parser from onionrcommands import parser
import onionrevents as events
setup.setup_config() setup.setup_config()
setup.setup_default_plugins() setup.setup_default_plugins()

View File

@ -23,7 +23,9 @@ from gevent.pywsgi import WSGIServer
from onionrutils import epoch from onionrutils import epoch
import httpapi, filepaths, logger import httpapi, filepaths, logger
from . import register_private_blueprints from . import register_private_blueprints
from etc import waitforsetvar
import serializeddata, config import serializeddata, config
from .. import public
class PrivateAPI: class PrivateAPI:
''' '''
Client HTTP api Client HTTP api
@ -48,8 +50,6 @@ class PrivateAPI:
self.clientToken = config.get('client.webpassword') self.clientToken = config.get('client.webpassword')
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode() self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
self.publicAPI = None # gets set when the thread calls our setter... bad hack but kinda necessary with flask
#threading.Thread(target=PublicAPI, args=(self,)).start()
self.host = httpapi.apiutils.setbindip.set_bind_IP(filepaths.private_API_host_file) self.host = httpapi.apiutils.setbindip.set_bind_IP(filepaths.private_API_host_file)
logger.info('Running api on %s:%s' % (self.host, self.bindPort)) logger.info('Running api on %s:%s' % (self.host, self.bindPort))
self.httpServer = '' self.httpServer = ''
@ -58,8 +58,12 @@ class PrivateAPI:
self.get_block_data = httpapi.apiutils.GetBlockData(self) self.get_block_data = httpapi.apiutils.GetBlockData(self)
register_private_blueprints.register_private_blueprints(self, app) register_private_blueprints.register_private_blueprints(self, app)
httpapi.load_plugin_blueprints(app) httpapi.load_plugin_blueprints(app)
self.app = app
self.httpServer = WSGIServer((self.host, bindPort), app, log=None, handler_class=httpapi.fdsafehandler.FDSafeHandler) def start(self):
waitforsetvar.wait_for_set_var(self, "_too_many")
self.publicAPI = self._too_many.get(public.PublicAPI)
self.httpServer = WSGIServer((self.host, self.bindPort), self.app, log=None, handler_class=httpapi.fdsafehandler.FDSafeHandler)
self.httpServer.serve_forever() self.httpServer.serve_forever()
def setPublicAPIInstance(self, inst): def setPublicAPIInstance(self, inst):

View File

@ -18,12 +18,21 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import time import time
import threading
import flask import flask
from gevent.pywsgi import WSGIServer from gevent.pywsgi import WSGIServer
from httpapi import apiutils, security, fdsafehandler, miscpublicapi from httpapi import apiutils, security, fdsafehandler, miscpublicapi
import logger, config, filepaths import logger, config, filepaths
from utils import gettransports from utils import gettransports
from etc import onionrvalues from etc import onionrvalues, waitforsetvar
def _get_tor_adder(pub_api):
transports = []
while len(transports) == 0:
transports = gettransports.get()
time.sleep(0.3)
pub_api.torAdder = transports[0]
class PublicAPI: class PublicAPI:
''' '''
The new client api server, isolated from the public api The new client api server, isolated from the public api
@ -34,11 +43,10 @@ class PublicAPI:
self.i2pEnabled = config.get('i2p.host', False) self.i2pEnabled = config.get('i2p.host', False)
self.hideBlocks = [] # Blocks to be denied sharing self.hideBlocks = [] # Blocks to be denied sharing
self.host = apiutils.setbindip.set_bind_IP(filepaths.public_API_host_file) self.host = apiutils.setbindip.set_bind_IP(filepaths.public_API_host_file)
transports = []
while len(transports) == 0: threading.Thread(target=_get_tor_adder, args=[self], daemon=True).start()
transports = gettransports.get()
time.sleep(0.3) self.torAdder = ""
self.torAdder = transports[0]
self.bindPort = config.get('client.public.port') self.bindPort = config.get('client.public.port')
self.lastRequest = 0 self.lastRequest = 0
self.hitCount = 0 # total rec requests to public api since server started self.hitCount = 0 # total rec requests to public api since server started
@ -46,8 +54,11 @@ class PublicAPI:
self.API_VERSION = onionrvalues.API_VERSION self.API_VERSION = onionrvalues.API_VERSION
logger.info('Running public api on %s:%s' % (self.host, self.bindPort)) logger.info('Running public api on %s:%s' % (self.host, self.bindPort))
app.register_blueprint(security.public.PublicAPISecurity(self).public_api_security_bp) app.register_blueprint(security.public.PublicAPISecurity(self).public_api_security_bp)
app.register_blueprint(miscpublicapi.endpoints.PublicEndpoints(self).public_endpoints_bp) app.register_blueprint(miscpublicapi.endpoints.PublicEndpoints(self).public_endpoints_bp)
self.httpServer = WSGIServer((self.host, self.bindPort), app, log=None, handler_class=fdsafehandler.FDSafeHandler) self.app = app
def start(self):
waitforsetvar.wait_for_set_var(self, "_too_many")
self.httpServer = WSGIServer((self.host, self.bindPort), self.app, log=None, handler_class=fdsafehandler.FDSafeHandler)
self.httpServer.serve_forever() self.httpServer.serve_forever()

View File

@ -32,22 +32,23 @@ from etc import humanreadabletime
import onionrservices, filepaths, storagecounter import onionrservices, filepaths, storagecounter
from coredb import daemonqueue, dbfiles from coredb import daemonqueue, dbfiles
from utils import gettransports from utils import gettransports
from netcontroller import NetController
OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers
config.reload() config.reload()
class OnionrCommunicatorDaemon: class OnionrCommunicatorDaemon:
def __init__(self, proxyPort, developmentMode=config.get('general.dev_mode', False)): def __init__(self, shared_state, developmentMode=config.get('general.dev_mode', False)):
# configure logger and stuff # configure logger and stuff
self.config = config self.config = config
self.storage_counter = storagecounter.StorageCounter() self.storage_counter = storagecounter.StorageCounter()
self.proxyPort = proxyPort
self.isOnline = True # Assume we're connected to the internet self.isOnline = True # Assume we're connected to the internet
self.shared_state = shared_state
# list of timer instances # list of timer instances
self.timers = [] self.timers = []
# initialize core with Tor socks port being 3rd argument # initialize core with Tor socks port being 3rd argument
self.proxyPort = proxyPort self.proxyPort = shared_state.get(NetController).socksPort
self.blocksToUpload = [] self.blocksToUpload = []
@ -158,6 +159,8 @@ class OnionrCommunicatorDaemon:
cleanupTimer.count = (cleanupTimer.frequency - 60) cleanupTimer.count = (cleanupTimer.frequency - 60)
blockCleanupTimer.count = (blockCleanupTimer.frequency - 5) blockCleanupTimer.count = (blockCleanupTimer.frequency - 5)
shared_state.add(self)
# Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking # Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking
try: try:
while not self.shutdown: while not self.shutdown:
@ -244,8 +247,8 @@ class OnionrCommunicatorDaemon:
self.decrementThreadCount('runCheck') self.decrementThreadCount('runCheck')
def startCommunicator(proxyPort): def startCommunicator(shared_state):
OnionrCommunicatorDaemon(proxyPort) OnionrCommunicatorDaemon(shared_state)
def run_file_exists(daemon): def run_file_exists(daemon):
if os.path.isfile(filepaths.run_check_file): if os.path.isfile(filepaths.run_check_file):

View File

@ -22,6 +22,7 @@ import onionrproofs, logger
from etc import onionrvalues from etc import onionrvalues
from onionrutils import basicrequests, bytesconverter from onionrutils import basicrequests, bytesconverter
from utils import gettransports from utils import gettransports
from netcontroller import NetController
from communicator import onlinepeers from communicator import onlinepeers
from coredb import keydb from coredb import keydb
def announce_node(daemon): def announce_node(daemon):
@ -77,7 +78,7 @@ def announce_node(daemon):
daemon.announceCache[peer] = data['random'] daemon.announceCache[peer] = data['random']
if not announceFail: if not announceFail:
logger.info('Announcing node to ' + url) logger.info('Announcing node to ' + url)
if basicrequests.do_post_request(daemon.onionrInst, url, data) == 'Success': if basicrequests.do_post_request(url, data, port=daemon.shared_state.get(NetController)) == 'Success':
logger.info('Successfully introduced node to ' + peer, terminal=True) logger.info('Successfully introduced node to ' + peer, terminal=True)
retData = True retData = True
keydb.transportinfo.set_address_info(peer, 'introduced', 1) keydb.transportinfo.set_address_info(peer, 'introduced', 1)

View File

@ -26,7 +26,7 @@ def handle_daemon_commands(comm_inst):
cmd = daemonqueue.daemon_queue() cmd = daemonqueue.daemon_queue()
response = '' response = ''
if cmd is not False: if cmd is not False:
events.event('daemon_command', onionr = comm_inst.onionrInst, data = {'cmd' : cmd}) events.event('daemon_command', data = {'cmd' : cmd})
if cmd[0] == 'shutdown': if cmd[0] == 'shutdown':
comm_inst.shutdown = True comm_inst.shutdown = True
elif cmd[0] == 'announceNode': elif cmd[0] == 'announceNode':

View File

@ -45,7 +45,7 @@ def upload_blocks_from_communicator(comm_inst):
data = {'block': block.Block(bl).getRaw()} data = {'block': block.Block(bl).getRaw()}
proxyType = proxypicker.pick_proxy(peer) proxyType = proxypicker.pick_proxy(peer)
logger.info("Uploading block to " + peer, terminal=True) logger.info("Uploading block to " + peer, terminal=True)
if not basicrequests.do_post_request(comm_inst.onionrInst, url, data=data, proxyType=proxyType) == False: if not basicrequests.do_post_request(url, data=data, proxyType=proxyType) == False:
localcommand.local_command('waitforshare/' + bl, post=True) localcommand.local_command('waitforshare/' + bl, post=True)
finishedUploads.append(bl) finishedUploads.append(bl)
for x in finishedUploads: for x in finishedUploads:

View File

@ -0,0 +1,4 @@
def wait_for_set_var(obj, attribute):
while True:
if hasattr(obj, attribute):
break

View File

@ -20,6 +20,7 @@
from flask import Response, Blueprint, request, send_from_directory, abort from flask import Response, Blueprint, request, send_from_directory, abort
from httpapi import apiutils from httpapi import apiutils
import onionrcrypto, config import onionrcrypto, config
from netcontroller import NetController
pub_key = onionrcrypto.pub_key pub_key = onionrcrypto.pub_key
class PrivateEndpoints: class PrivateEndpoints:
def __init__(self, client_api): def __init__(self, client_api):
@ -111,3 +112,7 @@ class PrivateEndpoints:
@private_endpoints_bp.route('/getHumanReadable/<name>') @private_endpoints_bp.route('/getHumanReadable/<name>')
def getHumanReadable(name): def getHumanReadable(name):
return Response(mnemonickeys.get_human_readable_ID(name)) return Response(mnemonickeys.get_human_readable_ID(name))
@private_endpoints_bp.route('/gettorsocks')
def get_tor_socks():
return Response(client_api._too_many.get(NetController).socksPort)

View File

@ -51,8 +51,13 @@ def daemon():
logger.debug('Runcheck file found on daemon start, deleting in advance.') logger.debug('Runcheck file found on daemon start, deleting in advance.')
os.remove(filepaths.run_check_file) os.remove(filepaths.run_check_file)
Thread(target=apiservers.ClientAPI, daemon=True).start() # Create shared object
Thread(target=apiservers.PublicAPI, daemon=True).start()
shared_state = toomanyobjs.TooMany()
Thread(target=shared_state.get(apiservers.ClientAPI).start, daemon=True).start()
Thread(target=shared_state.get(apiservers.PublicAPI).start, daemon=True).start()
shared_state.share_object() # share the parent object to the threads
apiHost = '' apiHost = ''
while apiHost == '': while apiHost == '':
@ -62,7 +67,6 @@ def daemon():
except FileNotFoundError: except FileNotFoundError:
pass pass
time.sleep(0.5) time.sleep(0.5)
#onionr.Onionr.setupConfig('data/', self = o_inst)
logger.raw('', terminal=True) logger.raw('', terminal=True)
# print nice header thing :) # print nice header thing :)
@ -73,7 +77,10 @@ def daemon():
if onionrvalues.DEVELOPMENT_MODE: if onionrvalues.DEVELOPMENT_MODE:
logger.warn('Development mode enabled', timestamp = False, terminal=True) logger.warn('Development mode enabled', timestamp = False, terminal=True)
net = NetController(config.get('client.public.port', 59497), apiServerIP=apiHost) net = NetController(config.get('client.public.port', 59497), apiServerIP=apiHost)
shared_state.add(net)
logger.info('Tor is starting...', terminal=True) logger.info('Tor is starting...', terminal=True)
if not net.startTor(): if not net.startTor():
localcommand.local_command('shutdown') localcommand.local_command('shutdown')
@ -88,9 +95,9 @@ def daemon():
time.sleep(1) time.sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
_proper_shutdown() _proper_shutdown()
events.event('init', threaded = False)
events.event('daemon_start') events.event('daemon_start')
communicator.startCommunicator(str(net.socksPort)) communicator.startCommunicator(shared_state)
localcommand.local_command('shutdown') localcommand.local_command('shutdown')

View File

@ -36,7 +36,7 @@ def add_peer(o_inst):
except AssertionError: except AssertionError:
logger.error('Failed to add key', terminal=True) logger.error('Failed to add key', terminal=True)
def add_address(o_inst): def add_address():
try: try:
newAddress = sys.argv[2] newAddress = sys.argv[2]
newAddress = newAddress.replace('http:', '').replace('/', '') newAddress = newAddress.replace('http:', '').replace('/', '')

View File

@ -1,12 +1,17 @@
from .. import onionrstatistics, version, daemonlaunch from .. import onionrstatistics, version, daemonlaunch, keyadders
import onionrexceptions import onionrexceptions
import onionrevents as events
def get_arguments(): def get_arguments():
'''This is a function because we need to be able to dynamically modify them with plugins''' '''This is a function because we need to be able to dynamically modify them with plugins'''
args = { args = {
('details', 'info'): onionrstatistics.show_details, ('details', 'info'): onionrstatistics.show_details,
('version'): version.version, ('version'): version.version,
('start', 'daemon'): daemonlaunch.start ('start', 'daemon'): daemonlaunch.start,
('stop', 'kill'): daemonlaunch.kill_daemon,
('add-address', 'addaddress', 'addadder'): keyadders.add_address
} }
args = events.event('init', data=args, threaded=False)
print(args)
return args return args
def get_help(): def get_help():

View File

@ -21,35 +21,35 @@
import config, logger, onionrplugins as plugins, onionrpluginapi as pluginapi import config, logger, onionrplugins as plugins, onionrpluginapi as pluginapi
from threading import Thread from threading import Thread
def get_pluginapi(onionr, data): def get_pluginapi(data):
return pluginapi.SharedAPI(onionr, data) return pluginapi.SharedAPI(data)
def __event_caller(event_name, data = {}, onionr = None): def __event_caller(event_name, data = {}):
''' '''
DO NOT call this function, this is for threading code only. DO NOT call this function, this is for threading code only.
Instead, call onionrevents.event Instead, call onionrevents.event
''' '''
for plugin in plugins.get_enabled_plugins(): for plugin in plugins.get_enabled_plugins():
try: try:
call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(onionr, data)) return call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(data))
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
logger.warn('Disabling nonexistant plugin "%s"...' % plugin, terminal=True) logger.warn('Disabling nonexistant plugin "%s"...' % plugin, terminal=True)
plugins.disable(plugin, onionr, stop_event = False) plugins.disable(plugin, stop_event = False)
except Exception as e: except Exception as e:
logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin), terminal=True) logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin), terminal=True)
logger.debug(str(e), terminal=True) logger.debug(str(e), terminal=True)
def event(event_name, data = {}, onionr = None, threaded = True): def event(event_name, data = {}, threaded = True):
''' '''
Calls an event on all plugins (if defined) Calls an event on all plugins (if defined)
''' '''
if threaded: if threaded:
thread = Thread(target = __event_caller, args = (event_name, data, onionr)) thread = Thread(target = __event_caller, args = (event_name, data))
thread.start() thread.start()
return thread return thread
else: else:
__event_caller(event_name, data, onionr) return __event_caller(event_name, data)
def call(plugin, event_name, data = None, pluginapi = None): def call(plugin, event_name, data = None, pluginapi = None):
''' '''
@ -61,7 +61,7 @@ def call(plugin, event_name, data = None, pluginapi = None):
attribute = 'on_' + str(event_name).lower() attribute = 'on_' + str(event_name).lower()
if hasattr(plugin, attribute): if hasattr(plugin, attribute):
getattr(plugin, attribute)(pluginapi, data) return getattr(plugin, attribute)(pluginapi, data)
return True return True
except Exception as e: except Exception as e:

View File

@ -23,7 +23,7 @@ from onionrutils import epoch
from . import scoresortedpeerlist, peerprofiles from . import scoresortedpeerlist, peerprofiles
import onionrblacklist, config import onionrblacklist, config
from coredb import keydb from coredb import keydb
def peer_cleanup(onionr_inst): def peer_cleanup():
'''Removes peers who have been offline too long or score too low''' '''Removes peers who have been offline too long or score too low'''
logger.info('Cleaning peers...') logger.info('Cleaning peers...')
blacklist = onionrblacklist.OnionrBlackList() blacklist = onionrblacklist.OnionrBlackList()

View File

@ -20,13 +20,14 @@
import requests, streamedrequests import requests, streamedrequests
import logger, onionrexceptions import logger, onionrexceptions
from etc import onionrvalues from etc import onionrvalues
def do_post_request(onionr_inst, url, data={}, port=0, proxyType='tor', max_size=10000): from . import localcommand
def do_post_request(url, data={}, port=0, proxyType='tor', max_size=10000):
''' '''
Do a POST request through a local tor or i2p instance Do a POST request through a local tor or i2p instance
''' '''
if proxyType == 'tor': if proxyType == 'tor':
if port == 0: if port == 0:
port = onionr_inst.torPort port = localcommand.local_command('/gettorsocks')
proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)} proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)}
elif proxyType == 'i2p': elif proxyType == 'i2p':
proxies = {'http': 'http://127.0.0.1:4444'} proxies = {'http': 'http://127.0.0.1:4444'}

View File

@ -20,8 +20,9 @@
import json import json
from coredb import blockmetadb from coredb import blockmetadb
import communicator
class SerializedData: class SerializedData:
def __init__(self, o_inst): def __init__(self):
''' '''
Serialized data is in JSON format: Serialized data is in JSON format:
{ {
@ -30,13 +31,14 @@ class SerializedData:
etc etc
} }
''' '''
self.o_inst = o_inst self._too_many = None
def getStats(self): def getStats(self):
'''Return statistics about our node''' '''Return statistics about our node'''
stats = {} stats = {}
stats['uptime'] = self.o_inst.communicatorInst.getUptime() comm_inst = self._too_many.get(communicator.OnionrCommunicatorDaemon)
stats['connectedNodes'] = '\n'.join(self.o_inst.communicatorInst.onlinePeers) stats['uptime'] = comm_inst.getUptime()
stats['connectedNodes'] = '\n'.join(comm_inst.onlinePeers)
stats['blockCount'] = len(blockmetadb.get_block_list()) stats['blockCount'] = len(blockmetadb.get_block_list())
stats['blockQueueCount'] = len(self.o_inst.communicatorInst.blockQueue) stats['blockQueueCount'] = len(comm_inst.blockQueue)
return json.dumps(stats) return json.dumps(stats)

View File

@ -107,9 +107,7 @@ def on_init(api, data = None):
global pluginapi global pluginapi
pluginapi = api pluginapi = api
flow = OnionrFlow() flow = OnionrFlow()
api.commands.register('flow', flow.start) return data
api.commands.register_help('flow', 'Open the flow messaging interface')
return
def on_processblocks(api, data=None): def on_processblocks(api, data=None):
b_hash = reconstructhash.deconstruct_hash(data['block'].hash) # Get the 0-truncated block hash b_hash = reconstructhash.deconstruct_hash(data['block'].hash) # Get the 0-truncated block hash

View File

@ -0,0 +1,9 @@
import time
def define_wait(dictionary, key, delay: int = 0):
while True:
try:
return dictionary[key]
except KeyError:
pass
if delay > 0:
time.sleep(delay)

View File

@ -1,7 +1,10 @@
import sys, os import sys, os
from . import readstatic from . import readstatic
import logger import logger
from etc import onionrvalues
def header(message = logger.colors.fg.pink + logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink + ' has started.'): def header(message = logger.colors.fg.pink + logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink + ' has started.'):
if onionrvalues.DEVELOPMENT_MODE:
return
header_path = readstatic.get_static_dir() + 'header.txt' header_path = readstatic.get_static_dir() + 'header.txt'
if os.path.exists(header_path) and logger.settings.get_level() <= logger.settings.LEVEL_INFO: if os.path.exists(header_path) and logger.settings.get_level() <= logger.settings.LEVEL_INFO:
with open(header_path, 'rb') as file: with open(header_path, 'rb') as file:

View File

@ -9,4 +9,4 @@ deadsimplekv==0.1.1
unpaddedbase32==0.1.0 unpaddedbase32==0.1.0
streamedrequests==1.0.0 streamedrequests==1.0.0
jinja2==2.10.1 jinja2==2.10.1
toomanyobjs==0.0.0 toomanyobjs==1.0.0

View File

@ -173,8 +173,8 @@ stem==1.7.1 \
--hash=sha256:c9eaf3116cb60c15995cbd3dec3a5cbc50e9bb6e062c4d6d42201e566f498ca2 --hash=sha256:c9eaf3116cb60c15995cbd3dec3a5cbc50e9bb6e062c4d6d42201e566f498ca2
streamedrequests==1.0.0 \ streamedrequests==1.0.0 \
--hash=sha256:1d9d07394804a6e1fd66bde74a804e71cab98e6920053865574a459f1cf7d3b7 --hash=sha256:1d9d07394804a6e1fd66bde74a804e71cab98e6920053865574a459f1cf7d3b7
toomanyobjs==0.0.0 \ toomanyobjs==1.0.0 \
--hash=sha256:997e9399a33d4884eb535b6cc2c02705ed9ae1bcff56afbbf3ea81fc4ac9ab95 --hash=sha256:040390188063dd00e5d903fd82a08850a175f9a384e09880d50acffb1e60ca70
unpaddedbase32==0.1.0 \ unpaddedbase32==0.1.0 \
--hash=sha256:5e4143fcaf77c9c6b4f60d18301c7570f0dac561dcf9b9aed8b5ba6ead7f218c --hash=sha256:5e4143fcaf77c9c6b4f60d18301c7570f0dac561dcf9b9aed8b5ba6ead7f218c
urllib3==1.24.2 \ urllib3==1.24.2 \