Various bug fixes
parent
34b919d324
commit
ddb3ce1e35
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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" : {
|
||||||
|
|
Loading…
Reference in New Issue