Various bug fixes

This commit is contained in:
Arinerron 2018-07-30 21:41:32 -07:00
parent 34b919d324
commit ddb3ce1e35
8 changed files with 60 additions and 31 deletions

View File

@ -24,7 +24,7 @@ from gevent.wsgi import WSGIServer
import sys, random, threading, hmac, hashlib, base64, time, math, os, logger, config import sys, random, threading, hmac, hashlib, base64, time, math, os, logger, config
from core import Core from core import Core
from onionrblockapi import Block from onionrblockapi import Block
import onionrutils, onionrcrypto, blockimporter import onionrutils, onionrcrypto, blockimporter, onionrevents as events
class API: class API:
''' '''
@ -94,6 +94,7 @@ class API:
''' '''
Simply define the request as not having yet failed, before every request. Simply define the request as not having yet failed, before every request.
''' '''
self.requestFailed = False self.requestFailed = False
return return
@ -119,16 +120,24 @@ class API:
@app.route('/client/ui/<path:path>') @app.route('/client/ui/<path:path>')
def webUI(path): def webUI(path):
startTime = math.floor(time.time()) startTime = math.floor(time.time())
if request.args.get('timingToken') is None: if request.args.get('timingToken') is None:
timingToken = '' timingToken = ''
else: else:
timingToken = request.args.get('timingToken') timingToken = request.args.get('timingToken')
self.validateHost('private')
if not config.get("onionr_ui.run", True):
abort(403)
if config.get("onionr_ui.private_only", True):
self.validateHost('private')
endTime = math.floor(time.time()) endTime = math.floor(time.time())
elapsed = endTime - startTime elapsed = endTime - startTime
if not hmac.compare_digest(timingToken, self.timeBypassToken): if not hmac.compare_digest(timingToken, self.timeBypassToken):
if elapsed < self._privateDelayTime: if elapsed < self._privateDelayTime:
time.sleep(self._privateDelayTime - elapsed) time.sleep(self._privateDelayTime - elapsed)
return send_from_directory('static-data/ui/dist/', path) return send_from_directory('static-data/ui/dist/', path)
@app.route('/client/') @app.route('/client/')
@ -150,6 +159,9 @@ class API:
if not self.validateToken(token): if not self.validateToken(token):
abort(403) abort(403)
events.event('webapi_private', onionr = None, data = {'action' : action, 'data' : data, 'timingToken' : timingToken, 'token' : token})
self.validateHost('private') self.validateHost('private')
if action == 'hello': if action == 'hello':
resp = Response('Hello, World! ' + request.host) resp = Response('Hello, World! ' + request.host)
@ -198,12 +210,12 @@ class API:
response['hash'] = hash response['hash'] = hash
response['reason'] = 'Successfully wrote block to file' response['reason'] = 'Successfully wrote block to file'
else: else:
response['reason'] = 'Faield to save the block' response['reason'] = 'Failed to save the block'
except Exception as e: except Exception as e:
logger.debug('insertBlock api request failed', error = e) logger.debug('insertBlock api request failed', error = e)
resp = Response(json.dumps(response)) resp = Response(json.dumps(response))
elif action in callbacks['private']: elif action in API.callbacks['private']:
resp = Response(str(getCallback(action, scope = 'private')(request))) resp = Response(str(getCallback(action, scope = 'private')(request)))
else: else:
resp = Response('(O_o) Dude what? (invalid command)') resp = Response('(O_o) Dude what? (invalid command)')
@ -257,6 +269,10 @@ class API:
data = data data = data
except: except:
data = '' data = ''
events.event('webapi_public', onionr = None, data = {'action' : action, 'data' : data, 'requestingPeer' : requestingPeer, 'request' : request})
if action == 'firstConnect': if action == 'firstConnect':
pass pass
elif action == 'ping': elif action == 'ping':
@ -299,7 +315,7 @@ class API:
peers = self._core.listPeers(getPow=True) peers = self._core.listPeers(getPow=True)
response = ','.join(peers) response = ','.join(peers)
resp = Response(response) resp = Response(response)
elif action in callbacks['public']: elif action in API.callbacks['public']:
resp = Response(str(getCallback(action, scope = 'public')(request))) resp = Response(str(getCallback(action, scope = 'public')(request)))
else: else:
resp = Response("") resp = Response("")
@ -373,29 +389,29 @@ class API:
sys.exit(1) sys.exit(1)
def setCallback(action, callback, scope = 'public'): def setCallback(action, callback, scope = 'public'):
if not scope in callbacks: if not scope in API.callbacks:
return False return False
callbacks[scope][action] = callback API.callbacks[scope][action] = callback
return True return True
def removeCallback(action, scope = 'public'): def removeCallback(action, scope = 'public'):
if (not scope in callbacks) or (not action in callbacks[scope]): if (not scope in API.callbacks) or (not action in API.callbacks[scope]):
return False return False
del callbacks[scope][action] del API.callbacks[scope][action]
return True return True
def getCallback(action, scope = 'public'): def getCallback(action, scope = 'public'):
if (not scope in callbacks) or (not action in callbacks[scope]): if (not scope in API.callbacks) or (not action in API.callbacks[scope]):
return None return None
return callbacks[scope][action] return API.callbacks[scope][action]
def getCallbacks(scope = None): def getCallbacks(scope = None):
if (not scope is None) and (scope in callbacks): if (not scope is None) and (scope in API.callbacks):
return callbacks[scope] return API.callbacks[scope]
return callbacks return API.callbacks

View File

@ -19,8 +19,8 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
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 sys, os, core, config, json, onionrblockapi as block, requests, time, logger, threading, onionrplugins as plugins, base64, onionr import sys, os, core, config, json, requests, time, logger, threading, base64, onionr
import onionrexceptions, onionrpeers import onionrexceptions, onionrpeers, onionrevents as events, onionrplugins as plugins, onionrblockapi as block
from defusedxml import minidom from defusedxml import minidom
class OnionrCommunicatorDaemon: class OnionrCommunicatorDaemon:
@ -337,6 +337,8 @@ class OnionrCommunicatorDaemon:
cmd = self._core.daemonQueue() cmd = self._core.daemonQueue()
if cmd is not False: if cmd is not False:
events.event('daemon_command', onionr = None, data = {'cmd' : cmd})
if cmd[0] == 'shutdown': if cmd[0] == 'shutdown':
self.shutdown = True self.shutdown = True
elif cmd[0] == 'announceNode': elif cmd[0] == 'announceNode':
@ -355,6 +357,7 @@ class OnionrCommunicatorDaemon:
threading.Thread(target=self.uploadBlock).start() threading.Thread(target=self.uploadBlock).start()
else: else:
logger.info('Recieved daemonQueue command:' + cmd[0]) logger.info('Recieved daemonQueue command:' + cmd[0])
self.decrementThreadCount('daemonCommands') self.decrementThreadCount('daemonCommands')
def uploadBlock(self): def uploadBlock(self):
@ -401,6 +404,7 @@ class OnionrCommunicatorDaemon:
time.sleep(1) time.sleep(1)
else: else:
# This executes if the api is NOT detected to be running # This executes if the api is NOT detected to be running
events.event('daemon_crash', onionr = None, data = {})
logger.error('Daemon detected API crash (or otherwise unable to reach API after long time), stopping...') logger.error('Daemon detected API crash (or otherwise unable to reach API after long time), stopping...')
self.shutdown = True self.shutdown = True
self.decrementThreadCount('detectAPICrash') self.decrementThreadCount('detectAPICrash')

View File

@ -100,7 +100,7 @@ DataDirectory data/tordata/
logger.fatal('Failed to start Tor. Try killing any other Tor processes owned by this user.') logger.fatal('Failed to start Tor. Try killing any other Tor processes owned by this user.')
return False return False
except KeyboardInterrupt: except KeyboardInterrupt:
logger.fatal("Got keyboard interrupt") logger.fatal("Got keyboard interrupt.")
return False return False
logger.debug('Finished starting Tor.', timestamp=True) logger.debug('Finished starting Tor.', timestamp=True)

View File

@ -40,9 +40,9 @@ except ImportError:
raise Exception("You need the PySocks module (for use with socks5 proxy to use Tor)") raise Exception("You need the PySocks module (for use with socks5 proxy to use Tor)")
ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech' ONIONR_TAGLINE = 'Anonymous P2P Platform - GPLv3 - https://Onionr.VoidNet.Tech'
ONIONR_VERSION = '0.1.0' # for debugging and stuff ONIONR_VERSION = '0.1.1' # for debugging and stuff
ONIONR_VERSION_TUPLE = tuple(ONIONR_VERSION.split('.')) # (MAJOR, MINOR, VERSION) ONIONR_VERSION_TUPLE = tuple(ONIONR_VERSION.split('.')) # (MAJOR, MINOR, VERSION)
API_VERSION = '4' # increments of 1; only change when something fundemental about how the API works changes. This way other nodes knows how to communicate without learning too much information about you. API_VERSION = '4' # increments of 1; only change when something fundemental about how the API works changes. This way other nodes know how to communicate without learning too much information about you.
class Onionr: class Onionr:
def __init__(self): def __init__(self):

View File

@ -33,10 +33,10 @@ def __event_caller(event_name, data = {}, onionr = None):
try: try:
call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(onionr, data)) call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(onionr, data))
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
logger.warn('Disabling nonexistant plugin \"' + plugin + '\"...') logger.warn('Disabling nonexistant plugin "%s"...' % plugin)
plugins.disable(plugin, onionr, stop_event = False) plugins.disable(plugin, onionr, stop_event = False)
except Exception as e: except Exception as e:
logger.warn('Event \"' + event_name + '\" failed for plugin \"' + plugin + '\".') logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin))
logger.debug(str(e)) logger.debug(str(e))

View File

@ -49,5 +49,6 @@ class InvalidProof(Exception):
# network level exceptions # network level exceptions
class MissingPort(Exception): class MissingPort(Exception):
pass pass
class InvalidAddress(Exception): class InvalidAddress(Exception):
pass pass

View File

@ -199,7 +199,7 @@ class OnionrUtils:
def getBlockMetadataFromData(self, blockData): def getBlockMetadataFromData(self, blockData):
''' '''
accepts block contents as string, returns a tuple of metadata, meta (meta being internal metadata, which will be returned as an encrypted base64 string if it is encrypted, dict if not). accepts block contents as string, returns a tuple of metadata, meta (meta being internal metadata, which will be returned as an encrypted base64 string if it is encrypted, dict if not).
''' '''
meta = {} meta = {}
metadata = {} metadata = {}
@ -208,7 +208,7 @@ class OnionrUtils:
blockData = blockData.encode() blockData = blockData.encode()
except AttributeError: except AttributeError:
pass pass
try: try:
metadata = json.loads(blockData[:blockData.find(b'\n')].decode()) metadata = json.loads(blockData[:blockData.find(b'\n')].decode())
except json.decoder.JSONDecodeError: except json.decoder.JSONDecodeError:
@ -221,7 +221,7 @@ class OnionrUtils:
meta = json.loads(metadata['meta']) meta = json.loads(metadata['meta'])
except KeyError: except KeyError:
pass pass
meta = metadata['meta'] meta = metadata['meta']
return (metadata, meta, data) return (metadata, meta, data)
def checkPort(self, port, host=''): def checkPort(self, port, host=''):
@ -251,7 +251,7 @@ class OnionrUtils:
return False return False
else: else:
return True return True
def processBlockMetadata(self, blockHash): def processBlockMetadata(self, blockHash):
''' '''
Read metadata from a block and cache it to the block database Read metadata from a block and cache it to the block database
@ -269,7 +269,7 @@ class OnionrUtils:
def escapeAnsi(self, line): def escapeAnsi(self, line):
''' '''
Remove ANSI escape codes from a string with regex Remove ANSI escape codes from a string with regex
taken or adapted from: https://stackoverflow.com/a/38662876 taken or adapted from: https://stackoverflow.com/a/38662876
''' '''
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]') ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
@ -331,12 +331,12 @@ class OnionrUtils:
retVal = False retVal = False
return retVal return retVal
def validateMetadata(self, metadata): def validateMetadata(self, metadata):
'''Validate metadata meets onionr spec (does not validate proof value computation), take in either dictionary or json string''' '''Validate metadata meets onionr spec (does not validate proof value computation), take in either dictionary or json string'''
# TODO, make this check sane sizes # TODO, make this check sane sizes
retData = False retData = False
# convert to dict if it is json string # convert to dict if it is json string
if type(metadata) is str: if type(metadata) is str:
try: try:
@ -382,7 +382,7 @@ class OnionrUtils:
else: else:
retVal = True retVal = True
return retVal return retVal
def isIntegerString(self, data): def isIntegerString(self, data):
'''Check if a string is a valid base10 integer''' '''Check if a string is a valid base10 integer'''
try: try:

View File

@ -2,8 +2,16 @@
"general" : { "general" : {
"dev_mode": true, "dev_mode": true,
"display_header" : true, "display_header" : true,
"dc_response": true,
"dc_execcallbacks" : true "direct_connect" : {
"respond" : true,
"execute_callbacks" : true
}
},
"onionr_ui" : {
"run" : true,
"private_only" : true
}, },
"client" : { "client" : {