Make Onionr more user friendly
This commit mostly just made messages more readable, worked on logger, and fixed a few bugs
This commit is contained in:
parent
22115891f2
commit
bb08162019
@ -24,7 +24,7 @@ from gevent.pywsgi import WSGIServer
|
||||
import sys, random, threading, hmac, hashlib, base64, time, math, os, json
|
||||
import core
|
||||
from onionrblockapi import Block
|
||||
import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config
|
||||
import onionrutils, onionrexceptions, onionrcrypto, blockimporter, onionrevents as events, logger, config, onionr
|
||||
|
||||
class API:
|
||||
'''
|
||||
@ -75,14 +75,8 @@ class API:
|
||||
This also saves the used host (random localhost IP address) to the data folder in host.txt
|
||||
'''
|
||||
|
||||
config.reload()
|
||||
|
||||
if config.get('dev_mode', True):
|
||||
self._developmentMode = True
|
||||
logger.set_level(logger.LEVEL_DEBUG)
|
||||
else:
|
||||
self._developmentMode = False
|
||||
logger.set_level(logger.LEVEL_INFO)
|
||||
# configure logger and stuff
|
||||
onionr.Onionr.setupConfig('data/', self = self)
|
||||
|
||||
self.debug = debug
|
||||
self._privateDelayTime = 3
|
||||
@ -131,14 +125,14 @@ class API:
|
||||
resp.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'none'; object-src 'none'; style-src data: 'unsafe-inline'; img-src data:; media-src 'none'; frame-src 'none'; font-src 'none'; connect-src 'none'"
|
||||
resp.headers['X-Frame-Options'] = 'deny'
|
||||
resp.headers['X-Content-Type-Options'] = "nosniff"
|
||||
resp.headers['api'] = API_VERSION
|
||||
resp.headers['X-API'] = API_VERSION
|
||||
|
||||
# reset to text/plain to help prevent browser attacks
|
||||
self.mimeType = 'text/plain'
|
||||
self.overrideCSP = False
|
||||
|
||||
return resp
|
||||
|
||||
|
||||
@app.route('/www/private/<path:path>')
|
||||
def www_private(path):
|
||||
startTime = math.floor(time.time())
|
||||
|
@ -21,12 +21,14 @@
|
||||
'''
|
||||
import sys, os, core, config, json, requests, time, logger, threading, base64, onionr, uuid
|
||||
import onionrexceptions, onionrpeers, onionrevents as events, onionrplugins as plugins, onionrblockapi as block
|
||||
import onionrdaemontools, onionrsockets, onionrchat
|
||||
import onionrdaemontools, onionrsockets, onionrchat, onionr
|
||||
from dependencies import secrets
|
||||
from defusedxml import minidom
|
||||
|
||||
class OnionrCommunicatorDaemon:
|
||||
def __init__(self, debug, developmentMode):
|
||||
# configure logger and stuff
|
||||
onionr.Onionr.setupConfig('data/', self = self)
|
||||
|
||||
self.isOnline = True # Assume we're connected to the internet
|
||||
|
||||
@ -303,9 +305,11 @@ class OnionrCommunicatorDaemon:
|
||||
self.decrementThreadCount('clearOfflinePeer')
|
||||
|
||||
def getOnlinePeers(self):
|
||||
'''Manages the self.onlinePeers attribute list, connects to more peers if we have none connected'''
|
||||
'''
|
||||
Manages the self.onlinePeers attribute list, connects to more peers if we have none connected
|
||||
'''
|
||||
|
||||
logger.info('Refreshing peer pool.')
|
||||
logger.debug('Refreshing peer pool...')
|
||||
maxPeers = int(config.get('peers.max_connect', 10))
|
||||
needed = maxPeers - len(self.onlinePeers)
|
||||
|
||||
@ -318,11 +322,13 @@ class OnionrCommunicatorDaemon:
|
||||
break
|
||||
else:
|
||||
if len(self.onlinePeers) == 0:
|
||||
logger.warn('Could not connect to any peer.')
|
||||
logger.debug('Couldn\'t connect to any peers.')
|
||||
self.decrementThreadCount('getOnlinePeers')
|
||||
|
||||
def addBootstrapListToPeerList(self, peerList):
|
||||
'''Add the bootstrap list to the peer list (no duplicates)'''
|
||||
'''
|
||||
Add the bootstrap list to the peer list (no duplicates)
|
||||
'''
|
||||
for i in self._core.bootstrapList:
|
||||
if i not in peerList and i not in self.offlinePeers and i != self._core.hsAddress and len(str(i).strip()) > 0:
|
||||
peerList.append(i)
|
||||
@ -440,11 +446,13 @@ class OnionrCommunicatorDaemon:
|
||||
def heartbeat(self):
|
||||
'''Show a heartbeat debug message'''
|
||||
currentTime = self._core._utils.getEpoch() - self.startTime
|
||||
logger.debug('heartbeat, running seconds: ' + str(currentTime))
|
||||
logger.debug('Heartbeat. Node online for %s.' % self.daemonTools.humanReadableTime(currentTime))
|
||||
self.decrementThreadCount('heartbeat')
|
||||
|
||||
def daemonCommands(self):
|
||||
'''process daemon commands from daemonQueue'''
|
||||
'''
|
||||
Process daemon commands from daemonQueue
|
||||
'''
|
||||
cmd = self._core.daemonQueue()
|
||||
|
||||
if cmd is not False:
|
||||
|
@ -73,6 +73,7 @@ LEVEL_INFO = 2
|
||||
LEVEL_WARN = 3
|
||||
LEVEL_ERROR = 4
|
||||
LEVEL_FATAL = 5
|
||||
LEVEL_IMPORTANT = 6
|
||||
|
||||
_type = OUTPUT_TO_CONSOLE | USE_ANSI # the default settings for logging
|
||||
_level = LEVEL_DEBUG # the lowest level to log
|
||||
@ -201,36 +202,36 @@ def confirm(default = 'y', message = 'Are you sure %s? '):
|
||||
return default == 'y'
|
||||
|
||||
# debug: when there is info that could be useful for debugging purposes only
|
||||
def debug(data, error = None, timestamp = True, prompt = True, sensitive = False):
|
||||
if get_level() <= LEVEL_DEBUG:
|
||||
log('/', data, timestamp=timestamp, prompt = prompt, sensitive = sensitive)
|
||||
def debug(data, error = None, timestamp = True, prompt = True, sensitive = False, level = LEVEL_DEBUG):
|
||||
if get_level() <= level:
|
||||
log('/', data, timestamp = timestamp, prompt = prompt, sensitive = sensitive)
|
||||
if not error is None:
|
||||
debug('Error: ' + str(error) + parse_error())
|
||||
|
||||
# info: when there is something to notify the user of, such as the success of a process
|
||||
def info(data, timestamp = False, prompt = True, sensitive = False):
|
||||
if get_level() <= LEVEL_INFO:
|
||||
def info(data, timestamp = False, prompt = True, sensitive = False, level = LEVEL_INFO):
|
||||
if get_level() <= level:
|
||||
log('+', data, colors.fg.green, timestamp = timestamp, prompt = prompt, sensitive = sensitive)
|
||||
|
||||
# warn: when there is a potential for something bad to happen
|
||||
def warn(data, error = None, timestamp = True, prompt = True, sensitive = False):
|
||||
def warn(data, error = None, timestamp = True, prompt = True, sensitive = False, level = LEVEL_WARN):
|
||||
if not error is None:
|
||||
debug('Error: ' + str(error) + parse_error())
|
||||
if get_level() <= LEVEL_WARN:
|
||||
if get_level() <= level:
|
||||
log('!', data, colors.fg.orange, timestamp = timestamp, prompt = prompt, sensitive = sensitive)
|
||||
|
||||
# error: when only one function, module, or process of the program encountered a problem and must stop
|
||||
def error(data, error = None, timestamp = True, prompt = True, sensitive = False):
|
||||
if get_level() <= LEVEL_ERROR:
|
||||
def error(data, error = None, timestamp = True, prompt = True, sensitive = False, level = LEVEL_ERROR):
|
||||
if get_level() <= level:
|
||||
log('-', data, colors.fg.red, timestamp = timestamp, fd = sys.stderr, prompt = prompt, sensitive = sensitive)
|
||||
if not error is None:
|
||||
debug('Error: ' + str(error) + parse_error())
|
||||
|
||||
# fatal: when the something so bad has happened that the program must stop
|
||||
def fatal(data, error = None, timestamp=True, prompt = True, sensitive = False):
|
||||
def fatal(data, error = None, timestamp=True, prompt = True, sensitive = False, level = LEVEL_FATAL):
|
||||
if not error is None:
|
||||
debug('Error: ' + str(error) + parse_error(), sensitive = sensitive)
|
||||
if get_level() <= LEVEL_FATAL:
|
||||
if get_level() <= level:
|
||||
log('#', data, colors.bg.red + colors.fg.green + colors.bold, timestamp = timestamp, fd = sys.stderr, prompt = prompt, sensitive = sensitive)
|
||||
|
||||
# returns a formatted error message
|
||||
|
@ -141,7 +141,7 @@ HashedControlPassword ''' + str(password) + '''
|
||||
logger.fatal('Failed to start Tor. Maybe a stray instance of Tor used by Onionr is still running?')
|
||||
return False
|
||||
except KeyboardInterrupt:
|
||||
logger.fatal("Got keyboard interrupt.")
|
||||
logger.fatal('Got keyboard interrupt.', timestamp = false, level = logger.LEVEL_IMPORTANT)
|
||||
return False
|
||||
|
||||
logger.debug('Finished starting Tor.', timestamp=True)
|
||||
|
151
onionr/onionr.py
151
onionr/onionr.py
@ -65,36 +65,7 @@ class Onionr:
|
||||
|
||||
# Load global configuration data
|
||||
|
||||
data_exists = os.path.exists(self.dataDir)
|
||||
|
||||
if not data_exists:
|
||||
os.mkdir(self.dataDir)
|
||||
|
||||
if os.path.exists('static-data/default_config.json'):
|
||||
config.set_config(json.loads(open('static-data/default_config.json').read())) # this is the default config, it will be overwritten if a config file already exists. Else, it saves it
|
||||
else:
|
||||
# the default config file doesn't exist, try hardcoded config
|
||||
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': self.dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
|
||||
if not data_exists:
|
||||
config.save()
|
||||
config.reload() # this will read the configuration file into memory
|
||||
|
||||
settings = 0b000
|
||||
if config.get('log.console.color', True):
|
||||
settings = settings | logger.USE_ANSI
|
||||
if config.get('log.console.output', True):
|
||||
settings = settings | logger.OUTPUT_TO_CONSOLE
|
||||
if config.get('log.file.output', True):
|
||||
settings = settings | logger.OUTPUT_TO_FILE
|
||||
logger.set_file(config.get('log.file.path', '/tmp/onionr.log').replace('data/', self.dataDir))
|
||||
logger.set_settings(settings)
|
||||
|
||||
if str(config.get('general.dev_mode', True)).lower() == 'true':
|
||||
self._developmentMode = True
|
||||
logger.set_level(logger.LEVEL_DEBUG)
|
||||
else:
|
||||
self._developmentMode = False
|
||||
logger.set_level(logger.LEVEL_INFO)
|
||||
data_exists = Onionr.setupConfig(self.dataDir, self = self)
|
||||
|
||||
self.onionrCore = core.Core()
|
||||
self.onionrUtils = onionrutils.OnionrUtils(self.onionrCore)
|
||||
@ -222,14 +193,18 @@ class Onionr:
|
||||
'help': 'Displays this Onionr help menu',
|
||||
'version': 'Displays the Onionr version',
|
||||
'config': 'Configures something and adds it to the file',
|
||||
|
||||
'start': 'Starts the Onionr daemon',
|
||||
'stop': 'Stops the Onionr daemon',
|
||||
|
||||
'stats': 'Displays node statistics',
|
||||
'get-password': 'Displays the web password',
|
||||
'details': 'Displays the web password, public key, and human readable public key',
|
||||
|
||||
'enable-plugin': 'Enables and starts a plugin',
|
||||
'disable-plugin': 'Disables and stops a plugin',
|
||||
'reload-plugin': 'Reloads a plugin',
|
||||
'create-plugin': 'Creates directory structure for a plugin',
|
||||
|
||||
'add-peer': 'Adds a peer to database',
|
||||
'list-peers': 'Displays a list of peers',
|
||||
'add-file': 'Create an Onionr block from a file',
|
||||
@ -357,7 +332,7 @@ class Onionr:
|
||||
return config.get('client.hmac')
|
||||
|
||||
def printWebPassword(self):
|
||||
print(self.getWebPassword())
|
||||
logger.info(self.getWebPassword(), sensitive = True)
|
||||
|
||||
def getHelp(self):
|
||||
return self.cmdhelp
|
||||
@ -410,16 +385,16 @@ class Onionr:
|
||||
THIS SECTION DEFINES THE COMMANDS
|
||||
'''
|
||||
|
||||
def version(self, verbosity=5):
|
||||
def version(self, verbosity = 5, function = logger.info):
|
||||
'''
|
||||
Displays the Onionr version
|
||||
'''
|
||||
|
||||
logger.info('Onionr %s (%s) - API v%s' % (ONIONR_VERSION, platform.machine(), API_VERSION))
|
||||
function('Onionr v%s (%s) (API v%s)' % (ONIONR_VERSION, platform.machine(), API_VERSION))
|
||||
if verbosity >= 1:
|
||||
logger.info(ONIONR_TAGLINE)
|
||||
function(ONIONR_TAGLINE)
|
||||
if verbosity >= 2:
|
||||
logger.info('Running on %s %s' % (platform.platform(), platform.release()))
|
||||
function('Running on %s %s' % (platform.platform(), platform.release()))
|
||||
|
||||
return
|
||||
|
||||
@ -635,35 +610,47 @@ class Onionr:
|
||||
logger.debug('Runcheck file found on daemon start, deleting in advance.')
|
||||
os.remove('data/.runcheck')
|
||||
|
||||
apiThread = Thread(target=api.API, args=(self.debug,API_VERSION))
|
||||
apiThread = Thread(target = api.API, args = (self.debug, API_VERSION))
|
||||
apiThread.start()
|
||||
|
||||
try:
|
||||
time.sleep(3)
|
||||
except KeyboardInterrupt:
|
||||
logger.info('Got keyboard interrupt')
|
||||
logger.debug('Got keyboard interrupt, shutting down...')
|
||||
time.sleep(1)
|
||||
self.onionrUtils.localCommand('shutdown')
|
||||
else:
|
||||
if apiThread.isAlive():
|
||||
# configure logger and stuff
|
||||
Onionr.setupConfig('data/', self = self)
|
||||
|
||||
if self._developmentMode:
|
||||
logger.warn('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)', timestamp = False)
|
||||
net = NetController(config.get('client.port', 59496))
|
||||
logger.info('Tor is starting...')
|
||||
logger.debug('Tor is starting...')
|
||||
if not net.startTor():
|
||||
sys.exit(1)
|
||||
logger.info('Started .onion service: ' + logger.colors.underline + net.myID)
|
||||
logger.info('Our Public key: ' + self.onionrCore._crypto.pubKey)
|
||||
logger.debug('Started .onion service: %s' % (logger.colors.underline + net.myID))
|
||||
logger.debug('Using public key: %s' % (logger.colors.underline + self.onionrCore._crypto.pubKey))
|
||||
time.sleep(1)
|
||||
#TODO make runable on windows
|
||||
communicatorProc = subprocess.Popen([communicatorDaemon, "run", str(net.socksPort)])
|
||||
# Print nice header thing :)
|
||||
# TODO: make runable on windows
|
||||
communicatorProc = subprocess.Popen([communicatorDaemon, 'run', str(net.socksPort)])
|
||||
|
||||
# print nice header thing :)
|
||||
if config.get('general.display_header', True):
|
||||
self.header()
|
||||
logger.debug('Started communicator')
|
||||
|
||||
# print out debug info
|
||||
self.version(verbosity = 5, function = logger.debug)
|
||||
logger.debug('Python version %s' % platform.python_version())
|
||||
|
||||
logger.debug('Started communicator.')
|
||||
|
||||
events.event('daemon_start', onionr = self)
|
||||
try:
|
||||
while True:
|
||||
time.sleep(5)
|
||||
|
||||
# Break if communicator process ends, so we don't have left over processes
|
||||
if communicatorProc.poll() is not None:
|
||||
break
|
||||
@ -810,7 +797,7 @@ class Onionr:
|
||||
except IndexError:
|
||||
logger.error("Syntax %s %s" % (sys.argv[0], '/path/to/filename <blockhash>'))
|
||||
else:
|
||||
print(fileName)
|
||||
logger.info(fileName)
|
||||
contents = None
|
||||
if os.path.exists(fileName):
|
||||
logger.error("File already exists")
|
||||
@ -842,17 +829,83 @@ class Onionr:
|
||||
else:
|
||||
logger.error('%s add-file <filename>' % sys.argv[0], timestamp = False)
|
||||
|
||||
def setupConfig(dataDir, self = None):
|
||||
data_exists = os.path.exists(dataDir)
|
||||
|
||||
if not data_exists:
|
||||
os.mkdir(dataDir)
|
||||
|
||||
if os.path.exists('static-data/default_config.json'):
|
||||
config.set_config(json.loads(open('static-data/default_config.json').read())) # this is the default config, it will be overwritten if a config file already exists. Else, it saves it
|
||||
else:
|
||||
# the default config file doesn't exist, try hardcoded config
|
||||
logger.warn('Default configuration file does not exist, switching to hardcoded fallback configuration!')
|
||||
config.set_config({'dev_mode': True, 'log': {'file': {'output': True, 'path': dataDir + 'output.log'}, 'console': {'output': True, 'color': True}}})
|
||||
if not data_exists:
|
||||
config.save()
|
||||
config.reload() # this will read the configuration file into memory
|
||||
|
||||
settings = 0b000
|
||||
if config.get('log.console.color', True):
|
||||
settings = settings | logger.USE_ANSI
|
||||
if config.get('log.console.output', True):
|
||||
settings = settings | logger.OUTPUT_TO_CONSOLE
|
||||
if config.get('log.file.output', True):
|
||||
settings = settings | logger.OUTPUT_TO_FILE
|
||||
logger.set_file(config.get('log.file.path', '/tmp/onionr.log').replace('data/', dataDir))
|
||||
logger.set_settings(settings)
|
||||
|
||||
if not self is None:
|
||||
if str(config.get('general.dev_mode', True)).lower() == 'true':
|
||||
self._developmentMode = True
|
||||
logger.set_level(logger.LEVEL_DEBUG)
|
||||
else:
|
||||
self._developmentMode = False
|
||||
logger.set_level(logger.LEVEL_INFO)
|
||||
|
||||
verbosity = str(config.get('log.verbosity', 'default')).lower().strip()
|
||||
if not verbosity in ['default', 'null', 'none', 'nil']:
|
||||
map = {
|
||||
str(logger.LEVEL_DEBUG) : logger.LEVEL_DEBUG,
|
||||
'verbose' : logger.LEVEL_DEBUG,
|
||||
'debug' : logger.LEVEL_DEBUG,
|
||||
str(logger.LEVEL_INFO) : logger.LEVEL_INFO,
|
||||
'info' : logger.LEVEL_INFO,
|
||||
'information' : logger.LEVEL_INFO,
|
||||
str(logger.LEVEL_WARN) : logger.LEVEL_WARN,
|
||||
'warn' : logger.LEVEL_WARN,
|
||||
'warning' : logger.LEVEL_WARN,
|
||||
'warnings' : logger.LEVEL_WARN,
|
||||
str(logger.LEVEL_ERROR) : logger.LEVEL_ERROR,
|
||||
'err' : logger.LEVEL_ERROR,
|
||||
'error' : logger.LEVEL_ERROR,
|
||||
'errors' : logger.LEVEL_ERROR,
|
||||
str(logger.LEVEL_FATAL) : logger.LEVEL_FATAL,
|
||||
'fatal' : logger.LEVEL_FATAL,
|
||||
str(logger.LEVEL_IMPORTANT) : logger.LEVEL_IMPORTANT,
|
||||
'silent' : logger.LEVEL_IMPORTANT,
|
||||
'quiet' : logger.LEVEL_IMPORTANT,
|
||||
'important' : logger.LEVEL_IMPORTANT
|
||||
}
|
||||
|
||||
if verbosity in map:
|
||||
logger.set_level(map[verbosity])
|
||||
else:
|
||||
logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity)
|
||||
|
||||
return data_exists
|
||||
|
||||
def openUI(self):
|
||||
url = 'http://127.0.0.1:%s/ui/index.html?timingToken=%s' % (config.get('client.port', 59496), self.onionrUtils.getTimeBypassToken())
|
||||
|
||||
print('Opening %s ...' % url)
|
||||
logger.info('Opening %s ...' % url)
|
||||
webbrowser.open(url, new = 1, autoraise = True)
|
||||
|
||||
def header(self, message = logger.colors.fg.pink + logger.colors.bold + 'Onionr' + logger.colors.reset + logger.colors.fg.pink + ' has started.'):
|
||||
if os.path.exists('static-data/header.txt'):
|
||||
if os.path.exists('static-data/header.txt') and logger.get_level() <= logger.LEVEL_INFO:
|
||||
with open('static-data/header.txt', 'rb') as file:
|
||||
# only to stdout, not file or log or anything
|
||||
sys.stderr.write(file.read().decode().replace('P', logger.colors.fg.pink).replace('W', logger.colors.reset + logger.colors.bold).replace('G', logger.colors.fg.green).replace('\n', logger.colors.reset + '\n').replace('B', logger.colors.bold).replace('V', ONIONR_VERSION))
|
||||
sys.stderr.write(file.read().decode().replace('P', logger.colors.fg.pink).replace('W', logger.colors.reset + logger.colors.bold).replace('G', logger.colors.fg.green).replace('\n', logger.colors.reset + '\n').replace('B', logger.colors.bold).replace('A', '%s' % API_VERSION).replace('V', ONIONR_VERSION))
|
||||
logger.info(logger.colors.fg.lightgreen + '-> ' + str(message) + logger.colors.reset + logger.colors.fg.lightgreen + ' <-\n')
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -46,4 +46,4 @@ class OnionrChat:
|
||||
self.communicator.socketClient.sendData(peer, "lol")
|
||||
except:
|
||||
pass
|
||||
time.sleep(2)
|
||||
time.sleep(2)
|
||||
|
@ -140,3 +140,23 @@ class DaemonTools:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def humanReadableTime(self, seconds):
|
||||
build = ''
|
||||
|
||||
units = {
|
||||
'year' : 31557600,
|
||||
'month' : (31557600 / 12),
|
||||
'day' : 86400,
|
||||
'hour' : 3600,
|
||||
'minute' : 60,
|
||||
'second' : 1
|
||||
}
|
||||
|
||||
for unit in units:
|
||||
amnt_unit = int(seconds / units[unit])
|
||||
if amnt_unit >= 1:
|
||||
seconds -= amnt_unit * units[unit]
|
||||
build += '%s %s' % (amnt_unit, unit) + ('s' if amnt_unit != 1 else '') + ' '
|
||||
|
||||
return build.strip()
|
||||
|
@ -77,7 +77,7 @@ def enable(name, onionr = None, start_event = True):
|
||||
else:
|
||||
enabled_plugins.append(name)
|
||||
config.set('plugins.enabled', enabled_plugins, True)
|
||||
|
||||
|
||||
if start_event is True:
|
||||
start(name)
|
||||
return True
|
||||
@ -234,7 +234,7 @@ def check():
|
||||
config.reload()
|
||||
|
||||
if not config.is_set('plugins'):
|
||||
logger.debug('Generating plugin config data...')
|
||||
logger.debug('Generating plugin configuration data...')
|
||||
config.set('plugins', {'enabled': []}, True)
|
||||
|
||||
if not os.path.exists(os.path.dirname(get_plugins_folder())):
|
||||
|
@ -72,7 +72,7 @@ class OnionrSocketServer:
|
||||
self._core.socketServerResponseData[myPeer] = ''
|
||||
|
||||
return retData
|
||||
|
||||
|
||||
def socketStarter(self):
|
||||
while not self._core.killSockets:
|
||||
try:
|
||||
@ -87,14 +87,14 @@ class OnionrSocketServer:
|
||||
def detectShutdown(self):
|
||||
while not self._core.killSockets:
|
||||
time.sleep(5)
|
||||
logger.info('Killing socket server')
|
||||
logger.debug('Killing socket server...')
|
||||
self.http_server.stop()
|
||||
|
||||
def addSocket(self, peer, reason=''):
|
||||
bindPort = 1337
|
||||
|
||||
assert len(reason) <= 12
|
||||
|
||||
|
||||
with stem.control.Controller.from_port(port=config.get('tor.controlPort')) as controller:
|
||||
controller.authenticate(config.get('tor.controlpassword'))
|
||||
|
||||
@ -106,7 +106,7 @@ class OnionrSocketServer:
|
||||
self._core.insertBlock(str(uuid.uuid4()), header='socket', sign=True, encryptType='asym', asymPeer=peer, meta={'reason': reason, 'address': socket.service_id + '.onion'})
|
||||
self._core.socketReasons[peer] = reason
|
||||
return
|
||||
|
||||
|
||||
class OnionrSocketClient:
|
||||
def __init__(self, coreInst):
|
||||
self.sockets = {} # pubkey: tor address
|
||||
@ -158,7 +158,7 @@ class OnionrSocketClient:
|
||||
postData = {'data': data}
|
||||
self.connPool[peer] = {'date': self._core._utils.getEpoch(), 'data': self._core._utils.doPostRequest('http://' + address + '/dc/', data=postData)}
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def getResponse(self, peer):
|
||||
retData = ''
|
||||
try:
|
||||
@ -166,6 +166,6 @@ class OnionrSocketClient:
|
||||
except KeyError:
|
||||
pass
|
||||
return
|
||||
|
||||
|
||||
def sendData(self, peer, data):
|
||||
self.sendData[peer] = data
|
||||
self.sendData[peer] = data
|
||||
|
@ -527,7 +527,7 @@ class OnionrUtils:
|
||||
|
||||
while True:
|
||||
time.sleep(interval)
|
||||
|
||||
|
||||
if not os.path.isfile(runcheck_file):
|
||||
return True
|
||||
elif time.time() - starttime >= timeout:
|
||||
@ -622,12 +622,14 @@ class OnionrUtils:
|
||||
else:
|
||||
return
|
||||
headers = {'user-agent': 'PyOnionr'}
|
||||
response_headers = dict()
|
||||
try:
|
||||
proxies = {'http': 'socks4a://127.0.0.1:' + str(port), 'https': 'socks4a://127.0.0.1:' + str(port)}
|
||||
r = requests.get(url, headers=headers, proxies=proxies, allow_redirects=False, timeout=(15, 30))
|
||||
# Check server is using same API version as us
|
||||
try:
|
||||
if r.headers['api'] != str(API_VERSION):
|
||||
response_headers = r.headers
|
||||
if r.headers['X-API'] != str(API_VERSION):
|
||||
raise onionrexceptions.InvalidAPIVersion
|
||||
except KeyError:
|
||||
raise onionrexceptions.InvalidAPIVersion
|
||||
@ -635,9 +637,12 @@ class OnionrUtils:
|
||||
except KeyboardInterrupt:
|
||||
raise KeyboardInterrupt
|
||||
except ValueError as e:
|
||||
logger.debug('Failed to make request', error = e)
|
||||
logger.debug('Failed to make GET request to %s' % url, error = e, sensitive = True)
|
||||
except onionrexceptions.InvalidAPIVersion:
|
||||
logger.debug("Node is using different API version :(")
|
||||
if 'X-API' in response_headers:
|
||||
logger.debug('Using API version %s. Cannot communicate with node\'s API version of %s.' % (API_VERSION, response_headers['X-API']))
|
||||
else:
|
||||
logger.debug('Using API version %s. API version was not sent with the request.' % API_VERSION)
|
||||
except requests.exceptions.RequestException as e:
|
||||
if not 'ConnectTimeoutError' in str(e) and not 'Request rejected or failed' in str(e):
|
||||
logger.debug('Error: %s' % str(e))
|
||||
@ -656,12 +661,12 @@ class OnionrUtils:
|
||||
retData = ''
|
||||
curTime = self.getRoundedEpoch(rounding)
|
||||
self.nistSaltTimestamp = curTime
|
||||
data = self.doGetRequest('https://beacon.nist.gov/rest/record/' + str(curTime), port=torPort)
|
||||
dataXML = minidom.parseString(data, forbid_dtd=True, forbid_entities=True, forbid_external=True)
|
||||
data = self.doGetRequest('https://beacon.nist.gov/rest/record/' + str(curTime), port = torPort)
|
||||
dataXML = minidom.parseString(data, forbid_dtd = True, forbid_entities = True, forbid_external = True)
|
||||
try:
|
||||
retData = dataXML.getElementsByTagName('outputValue')[0].childNodes[0].data
|
||||
except ValueError:
|
||||
logger.warn('Could not get NIST beacon value')
|
||||
logger.warn('Failed to get the NIST beacon value.')
|
||||
else:
|
||||
self.powSalt = retData
|
||||
return retData
|
||||
|
@ -38,13 +38,12 @@ class OnionrCLIUI:
|
||||
pass
|
||||
|
||||
def refresh(self):
|
||||
for i in range(100):
|
||||
print('')
|
||||
print('\n' * 80 + logger.colors.reset)
|
||||
|
||||
def start(self):
|
||||
'''Main CLI UI interface menu'''
|
||||
showMenu = True
|
||||
isOnline = "No"
|
||||
isOnline = 'No'
|
||||
firstRun = True
|
||||
choice = ''
|
||||
|
||||
@ -53,7 +52,7 @@ class OnionrCLIUI:
|
||||
|
||||
while showMenu:
|
||||
if firstRun:
|
||||
logger.info("please wait while Onionr starts...")
|
||||
logger.info('Please wait while Onionr starts...'')
|
||||
daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL)
|
||||
time.sleep(30)
|
||||
firstRun = False
|
||||
@ -63,9 +62,8 @@ class OnionrCLIUI:
|
||||
else:
|
||||
isOnline = "No"
|
||||
|
||||
print('''
|
||||
Daemon Running: ''' + isOnline + '''
|
||||
|
||||
logger.info('''Daemon Running: ''' + isOnline + '''
|
||||
|
||||
1. Flow (Anonymous public chat, use at your own risk)
|
||||
2. Mail (Secure email-like service)
|
||||
3. File Sharing
|
||||
@ -83,7 +81,7 @@ Daemon Running: ''' + isOnline + '''
|
||||
elif choice in ("2", "mail"):
|
||||
self.subCommand("mail")
|
||||
elif choice in ("3", "file sharing", "file"):
|
||||
print("Not supported yet")
|
||||
logger.warn("Not supported yet")
|
||||
elif choice in ("4", "user settings", "settings"):
|
||||
try:
|
||||
self.setName()
|
||||
@ -91,21 +89,21 @@ Daemon Running: ''' + isOnline + '''
|
||||
pass
|
||||
elif choice in ("5", "daemon"):
|
||||
if isOnline == "Yes":
|
||||
print("Onionr daemon will shutdown...")
|
||||
logger.info("Onionr daemon will shutdown...")
|
||||
self.myCore.daemonQueueAdd('shutdown')
|
||||
try:
|
||||
daemon.kill()
|
||||
except UnboundLocalError:
|
||||
pass
|
||||
else:
|
||||
print("Starting Daemon...")
|
||||
logger.info("Starting Daemon...")
|
||||
daemon = subprocess.Popen(["./onionr.py", "start"], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||
elif choice in ("6", "quit"):
|
||||
showMenu = False
|
||||
elif choice == "":
|
||||
pass
|
||||
else:
|
||||
print("Invalid choice")
|
||||
logger.error("Invalid choice")
|
||||
return
|
||||
|
||||
def setName(self):
|
||||
|
@ -71,7 +71,7 @@ class PlainEncryption:
|
||||
plaintext = data
|
||||
encrypted = self.api.get_core()._crypto.pubKeyEncrypt(plaintext, pubkey, anonymous=True, encodedData=True)
|
||||
encrypted = self.api.get_core()._utils.bytesToStr(encrypted)
|
||||
print('ONIONR ENCRYPTED DATA %s END ENCRYPTED DATA' % (encrypted,))
|
||||
logger.info('Encrypted Message: \n\nONIONR ENCRYPTED DATA %s END ENCRYPTED DATA' % (encrypted,))
|
||||
def decrypt(self):
|
||||
plaintext = ""
|
||||
data = ""
|
||||
@ -89,10 +89,10 @@ class PlainEncryption:
|
||||
myPub = self.api.get_core()._crypto.pubKey
|
||||
decrypted = self.api.get_core()._crypto.pubKeyDecrypt(encrypted, privkey=self.api.get_core()._crypto.privKey, anonymous=True, encodedData=True)
|
||||
if decrypted == False:
|
||||
print("Decryption failed")
|
||||
logger.error("Decryption failed")
|
||||
else:
|
||||
data = json.loads(decrypted)
|
||||
print(data['data'])
|
||||
logger.info('Decrypted Message: \n\n%s' % data['data'])
|
||||
try:
|
||||
logger.info("Signing public key: %s" % (data['signer'],))
|
||||
assert self.api.get_core()._crypto.edVerify(data['data'], data['signer'], data['sig']) != False
|
||||
@ -101,7 +101,7 @@ class PlainEncryption:
|
||||
else:
|
||||
logger.info("Message has good signature.")
|
||||
return
|
||||
|
||||
|
||||
|
||||
def on_init(api, data = None):
|
||||
'''
|
||||
@ -114,4 +114,4 @@ def on_init(api, data = None):
|
||||
encrypt = PlainEncryption(pluginapi)
|
||||
api.commands.register(['encrypt'], encrypt.encrypt)
|
||||
api.commands.register(['decrypt'], encrypt.decrypt)
|
||||
return
|
||||
return
|
||||
|
@ -132,10 +132,10 @@ def createRepository(plugins):
|
||||
contents = {'plugins' : plugins, 'author' : getpass.getuser(), 'compiled-by' : plugin_name}
|
||||
|
||||
block = Block(core = pluginapi.get_core())
|
||||
|
||||
|
||||
block.setType('repository')
|
||||
block.setContent(json.dumps(contents))
|
||||
|
||||
|
||||
return block.save(True)
|
||||
|
||||
def check():
|
||||
@ -217,7 +217,7 @@ def pluginToBlock(plugin, import_block = True):
|
||||
info = ''
|
||||
with open(directory + 'info.json').read() as file:
|
||||
info = json.loads(file.read())
|
||||
|
||||
|
||||
if 'author' in info:
|
||||
author = info['author']
|
||||
if 'description' in info:
|
||||
@ -228,10 +228,10 @@ def pluginToBlock(plugin, import_block = True):
|
||||
metadata = {'author' : author, 'date' : str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')), 'name' : plugin, 'info' : info, 'compiled-by' : plugin_name, 'content' : data.decode('utf-8'), 'description' : description}
|
||||
|
||||
block = Block(core = pluginapi.get_core())
|
||||
|
||||
|
||||
block.setType('plugin')
|
||||
block.setContent(json.dumps(metadata))
|
||||
|
||||
|
||||
hash = block.save(True)
|
||||
# hash = pluginapi.get_core().insertBlock(, header = 'plugin', sign = True)
|
||||
|
||||
@ -390,12 +390,12 @@ def commandInstallPlugin():
|
||||
except Exception as e:
|
||||
logger.warn('Failed to lookup plugin in repositories.', timestamp = False)
|
||||
logger.error('asdf', error = e, timestamp = False)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
if pkobh is None:
|
||||
logger.error('No key for this plugin found in keystore or repositories, please specify.', timestamp = False)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
valid_hash = pluginapi.get_utils().validateHash(pkobh)
|
||||
@ -552,49 +552,48 @@ def commandPublishPlugin():
|
||||
logger.error('Plugin %s does not exist.' % pluginname, timestamp = False)
|
||||
else:
|
||||
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' <plugin>')
|
||||
|
||||
|
||||
def commandCreateRepository():
|
||||
if len(sys.argv) >= 3:
|
||||
check()
|
||||
|
||||
|
||||
plugins = list()
|
||||
script = sys.argv[0]
|
||||
|
||||
|
||||
del sys.argv[:2]
|
||||
success = True
|
||||
for pluginname in sys.argv:
|
||||
distributor = None
|
||||
|
||||
|
||||
if ':' in pluginname:
|
||||
split = pluginname.split(':')
|
||||
pluginname = split[0]
|
||||
distributor = split[1]
|
||||
|
||||
|
||||
pluginname = sanitize(pluginname)
|
||||
|
||||
|
||||
if distributor is None:
|
||||
distributor = getKey(pluginname)
|
||||
if distributor is None:
|
||||
logger.error('No distributor key was found for the plugin %s.' % pluginname, timestamp = False)
|
||||
success = False
|
||||
|
||||
|
||||
plugins.append([pluginname, distributor])
|
||||
|
||||
|
||||
if not success:
|
||||
logger.error('Please correct the above errors, then recreate the repository.')
|
||||
return True
|
||||
|
||||
|
||||
blockhash = createRepository(plugins)
|
||||
print(blockhash)
|
||||
if not blockhash is None:
|
||||
logger.info('Successfully created repository. Execute the following command to add the repository:\n ' + logger.colors.underline + '%s --add-repository %s' % (script, blockhash))
|
||||
else:
|
||||
logger.error('Failed to create repository, an unknown error occurred.')
|
||||
else:
|
||||
logger.info(sys.argv[0] + ' ' + sys.argv[1] + ' [plugins...]')
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# event listeners
|
||||
|
||||
def on_init(api, data = None):
|
||||
|
@ -66,7 +66,7 @@ class OnionrMail:
|
||||
self.sentboxList = []
|
||||
self.sentMessages = {}
|
||||
return
|
||||
|
||||
|
||||
def inbox(self):
|
||||
blockCount = 0
|
||||
pmBlockMap = {}
|
||||
@ -87,7 +87,7 @@ class OnionrMail:
|
||||
continue
|
||||
blockCount += 1
|
||||
pmBlockMap[blockCount] = blockHash
|
||||
|
||||
|
||||
block = pmBlocks[blockHash]
|
||||
senderKey = block.signer
|
||||
try:
|
||||
@ -102,7 +102,7 @@ class OnionrMail:
|
||||
displayList.append('%s. %s - %s: %s' % (blockCount, blockDate, senderDisplay[:12], blockHash))
|
||||
#displayList.reverse()
|
||||
for i in displayList:
|
||||
print(i)
|
||||
logger.info(i)
|
||||
try:
|
||||
choice = logger.readline('Enter a block number, -r to refresh, or -q to stop: ').strip().lower()
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
@ -129,16 +129,16 @@ class OnionrMail:
|
||||
else:
|
||||
cancel = ''
|
||||
readBlock.verifySig()
|
||||
print('Message recieved from %s' % (self.myCore._utils.bytesToStr(readBlock.signer,)))
|
||||
print('Valid signature:', readBlock.validSig)
|
||||
logger.info('Message recieved from %s' % (self.myCore._utils.bytesToStr(readBlock.signer,)))
|
||||
logger.info('Valid signature: %s' % readBlock.validSig)
|
||||
if not readBlock.validSig:
|
||||
logger.warn('This message has an INVALID signature. ANYONE could have sent this message.')
|
||||
cancel = logger.readline('Press enter to continue to message, or -q to not open the message (recommended).')
|
||||
if cancel != '-q':
|
||||
print(draw_border(self.myCore._utils.escapeAnsi(readBlock.bcontent.decode().strip())))
|
||||
input("Press enter to continue")
|
||||
logger.readline("Press enter to continue")
|
||||
return
|
||||
|
||||
|
||||
def sentbox(self):
|
||||
'''
|
||||
Display sent mail messages
|
||||
@ -146,7 +146,7 @@ class OnionrMail:
|
||||
entering = True
|
||||
while entering:
|
||||
self.getSentList()
|
||||
print('Enter block number or -q to return')
|
||||
logger.info('Enter block number or -q to return')
|
||||
try:
|
||||
choice = input('>')
|
||||
except (EOFError, KeyboardInterrupt) as e:
|
||||
@ -158,21 +158,21 @@ class OnionrMail:
|
||||
try:
|
||||
self.sentboxList[int(choice) - 1]
|
||||
except IndexError:
|
||||
print('Invalid block')
|
||||
logger.warn('Invalid block.')
|
||||
else:
|
||||
logger.info('Sent to: ' + self.sentMessages[self.sentboxList[int(choice) - 1]][1])
|
||||
# Print ansi escaped sent message
|
||||
print(self.myCore._utils.escapeAnsi(self.sentMessages[self.sentboxList[int(choice) - 1]][0]))
|
||||
logger.info(self.myCore._utils.escapeAnsi(self.sentMessages[self.sentboxList[int(choice) - 1]][0]))
|
||||
input('Press enter to continue...')
|
||||
|
||||
return
|
||||
|
||||
|
||||
def getSentList(self):
|
||||
count = 1
|
||||
for i in self.sentboxTools.listSent():
|
||||
self.sentboxList.append(i['hash'])
|
||||
self.sentMessages[i['hash']] = (i['message'], i['peer'])
|
||||
print('%s. %s - %s - %s' % (count, i['hash'], i['peer'][:12], i['date']))
|
||||
logger.info('%s. %s - %s - %s' % (count, i['hash'], i['peer'][:12], i['date']))
|
||||
count += 1
|
||||
|
||||
def draftMessage(self):
|
||||
@ -198,7 +198,7 @@ class OnionrMail:
|
||||
# if -q or ctrl-c/d, exit function here, otherwise we successfully got the public key
|
||||
return
|
||||
|
||||
print('Enter your message, stop by entering -q on a new line.')
|
||||
logger.info('Enter your message, stop by entering -q on a new line.')
|
||||
while newLine != '-q':
|
||||
try:
|
||||
newLine = input()
|
||||
@ -209,7 +209,7 @@ class OnionrMail:
|
||||
newLine += '\n'
|
||||
message += newLine
|
||||
|
||||
print('Inserting encrypted message as Onionr block....')
|
||||
logger.info('Inserting encrypted message as Onionr block....')
|
||||
|
||||
blockID = self.myCore.insertBlock(message, header='pm', encryptType='asym', asymPeer=recip, sign=True)
|
||||
self.sentboxTools.addToSent(blockID, recip, message)
|
||||
@ -217,7 +217,7 @@ class OnionrMail:
|
||||
choice = ''
|
||||
while True:
|
||||
|
||||
print(self.strings.programTag + '\n\nOur ID: ' + self.myCore._crypto.pubKey + self.strings.mainMenu.title()) # print out main menu
|
||||
logger.info(self.strings.programTag + '\n\nOur ID: ' + self.myCore._crypto.pubKey + self.strings.mainMenu.title()) # print out main menu
|
||||
|
||||
try:
|
||||
choice = logger.readline('Enter 1-%s:\n' % (len(self.strings.mainMenuChoices))).lower().strip()
|
||||
@ -251,4 +251,4 @@ def on_init(api, data = None):
|
||||
mail = OnionrMail(pluginapi)
|
||||
api.commands.register(['mail'], mail.menu)
|
||||
api.commands.register_help('mail', 'Interact with OnionrMail')
|
||||
return
|
||||
return
|
||||
|
@ -2,6 +2,7 @@
|
||||
"general" : {
|
||||
"dev_mode" : true,
|
||||
"display_header" : true,
|
||||
|
||||
"minimum_block_pow": 5,
|
||||
"minimum_send_pow": 5,
|
||||
|
||||
@ -34,7 +35,20 @@
|
||||
"client" : {
|
||||
|
||||
},
|
||||
"log": {
|
||||
|
||||
"plugins" : {
|
||||
"enabled" : {
|
||||
|
||||
},
|
||||
|
||||
"disabled" : {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
"log" : {
|
||||
"verbosity" : "default",
|
||||
|
||||
"file": {
|
||||
"output": false,
|
||||
"path": "data/output.log"
|
||||
|
@ -3,9 +3,9 @@ P G'
|
||||
P G''
|
||||
P G'' '
|
||||
P G''''''
|
||||
P :G;'''''P:
|
||||
P ::G;'''P::
|
||||
P :::G;;P:::
|
||||
P :G''''''P:
|
||||
P ::G''''P::
|
||||
P :::G''P:::
|
||||
P ::::::::
|
||||
P ::::::::::::
|
||||
P :::::::::::::::
|
||||
@ -20,6 +20,7 @@ P :::: ::::: ::::: ::: W :::: :: :: :: ::::: :: :: :: ::
|
||||
P :::: :::::: :::::: ::::
|
||||
P :::: :::::::::::: :::: GvPBV
|
||||
P ::::: :::::::: ::::
|
||||
P ::::: ::::::
|
||||
P ::::: :::::
|
||||
P ::::::::::::::::
|
||||
P :::::::
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user