diff --git a/onionr/api.py b/onionr/api.py index 06a1085d..3af4add9 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -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/') def www_private(path): startTime = math.floor(time.time()) diff --git a/onionr/communicator2.py b/onionr/communicator2.py index 41a239eb..d57b7b66 100755 --- a/onionr/communicator2.py +++ b/onionr/communicator2.py @@ -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: diff --git a/onionr/logger.py b/onionr/logger.py index 5adc0f3c..7a8172b3 100644 --- a/onionr/logger.py +++ b/onionr/logger.py @@ -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 diff --git a/onionr/netcontroller.py b/onionr/netcontroller.py index 1fea7925..a6141aeb 100644 --- a/onionr/netcontroller.py +++ b/onionr/netcontroller.py @@ -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) diff --git a/onionr/onionr.py b/onionr/onionr.py index 2c2505f4..819a3d8d 100755 --- a/onionr/onionr.py +++ b/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 ')) 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 ' % 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__": diff --git a/onionr/onionrchat.py b/onionr/onionrchat.py index 80569e6e..782266f8 100644 --- a/onionr/onionrchat.py +++ b/onionr/onionrchat.py @@ -46,4 +46,4 @@ class OnionrChat: self.communicator.socketClient.sendData(peer, "lol") except: pass - time.sleep(2) \ No newline at end of file + time.sleep(2) diff --git a/onionr/onionrdaemontools.py b/onionr/onionrdaemontools.py index afb272e0..3adeb5ea 100644 --- a/onionr/onionrdaemontools.py +++ b/onionr/onionrdaemontools.py @@ -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() diff --git a/onionr/onionrplugins.py b/onionr/onionrplugins.py index ce038856..aa45dcca 100644 --- a/onionr/onionrplugins.py +++ b/onionr/onionrplugins.py @@ -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())): diff --git a/onionr/onionrsockets.py b/onionr/onionrsockets.py index f20ad4f8..6ff08366 100644 --- a/onionr/onionrsockets.py +++ b/onionr/onionrsockets.py @@ -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 \ No newline at end of file + self.sendData[peer] = data diff --git a/onionr/onionrutils.py b/onionr/onionrutils.py index fd1ab693..956b2e22 100644 --- a/onionr/onionrutils.py +++ b/onionr/onionrutils.py @@ -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 diff --git a/onionr/static-data/default-plugins/cliui/main.py b/onionr/static-data/default-plugins/cliui/main.py index 646aa7c2..c29465f4 100644 --- a/onionr/static-data/default-plugins/cliui/main.py +++ b/onionr/static-data/default-plugins/cliui/main.py @@ -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): diff --git a/onionr/static-data/default-plugins/encrypt/main.py b/onionr/static-data/default-plugins/encrypt/main.py index 2aa87dcb..299f202e 100644 --- a/onionr/static-data/default-plugins/encrypt/main.py +++ b/onionr/static-data/default-plugins/encrypt/main.py @@ -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 \ No newline at end of file + return diff --git a/onionr/static-data/default-plugins/pluginmanager/main.py b/onionr/static-data/default-plugins/pluginmanager/main.py index 4812cc90..45f2b47f 100644 --- a/onionr/static-data/default-plugins/pluginmanager/main.py +++ b/onionr/static-data/default-plugins/pluginmanager/main.py @@ -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] + ' ') - + 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): diff --git a/onionr/static-data/default-plugins/pms/main.py b/onionr/static-data/default-plugins/pms/main.py index d05ff36f..45abd506 100644 --- a/onionr/static-data/default-plugins/pms/main.py +++ b/onionr/static-data/default-plugins/pms/main.py @@ -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 \ No newline at end of file + return diff --git a/onionr/static-data/default_config.json b/onionr/static-data/default_config.json index 73b3647d..d2cde4c8 100644 --- a/onionr/static-data/default_config.json +++ b/onionr/static-data/default_config.json @@ -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" diff --git a/onionr/static-data/header.txt b/onionr/static-data/header.txt index 92664951..e9366187 100644 --- a/onionr/static-data/header.txt +++ b/onionr/static-data/header.txt @@ -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 ::::::: +