def setup_default_plugins(): # Copy default plugins into plugins folder if not os.path.exists(plugins.get_plugins_folder()): if os.path.exists(get_static_dir() + '/default-plugins/'): names = [f for f in os.listdir(get_static_dir() + '/default-plugins/')] try: shutil.copytree( get_static_dir() + '/default-plugins/', plugins.get_plugins_folder()) except FileExistsError: pass # Enable plugins for name in names: if not name in plugins.get_enabled_plugins(): plugins.enable(name) for name in plugins.get_enabled_plugins(): if not os.path.exists(plugins.get_plugin_data_folder(name)): try: os.mkdir(plugins.get_plugin_data_folder(name)) except FileExistsError: pass except Exception as e: #logger.warn('Error enabling plugin: ' + str(e), terminal=True) plugins.disable(name, stop_event = False)
def register_plugin_commands(cmd) -> bool: plugin_cmd = plugin_command(cmd) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, plugin_cmd): getattr(pl, plugin_cmd)(onionrpluginapi.PluginAPI) return True return False
def __init__(self, apiInst): self.api = apiInst self.myCore = apiInst.get_core() self.shutdown = False self.running = 'undetermined' enabled = onionrplugins.get_enabled_plugins() self.mail_enabled = 'pms' in enabled self.flow_enabled = 'flow' in enabled
def load_plugin_blueprints(flaskapp, blueprint='flask_blueprint'): '''Iterate enabled plugins and load any http endpoints they have''' for plugin in onionrplugins.get_enabled_plugins(): plugin = onionrplugins.get_plugin(plugin) try: flaskapp.register_blueprint(getattr(plugin, blueprint)) except AttributeError: pass
def register_plugin_commands(cmd) -> bool: """Find a plugin command hook and execute it for a given cmd.""" plugin_cmd = plugin_command(cmd) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, plugin_cmd): getattr(pl, plugin_cmd)(onionrpluginapi.PluginAPI) return True return False
def event(event_name, data=None, onionr=None): ''' Calls an event on all plugins (if defined) ''' for plugin in plugins.get_enabled_plugins(): try: call(plugins.get_plugin(plugin), event_name, data, onionr) except: logger.warn('Event \"' + event_name + '\" failed for plugin \"' + plugin + '\".')
def load_plugin_security_whitelist_endpoints(whitelist: list): """Accept a list reference of whitelist endpoints from security/client.py and append plugin's specified endpoints to them by attribute""" for plugin in onionrplugins.get_enabled_plugins(): try: plugin = onionrplugins.get_plugin(plugin) except FileNotFoundError: continue try: whitelist.extend(getattr(plugin, "security_whitelist")) except AttributeError: pass
def load_plugin_blueprints(flaskapp, blueprint: str = 'flask_blueprint'): """Iterate enabled plugins and load any http endpoints they have""" config.reload() disabled = config.get('plugins.disabled') for plugin in onionrplugins.get_enabled_plugins(): if plugin in disabled: continue plugin = onionrplugins.get_plugin(plugin) try: flaskapp.register_blueprint(getattr(plugin, blueprint)) except AttributeError: pass
def __event_caller(event_name, data = {}, onionr = None): ''' DO NOT call this function, this is for threading code only. Instead, call onionrevents.event ''' for plugin in plugins.get_enabled_plugins(): try: call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(onionr, data)) except ModuleNotFoundError as e: logger.warn('Disabling nonexistant plugin "%s"...' % plugin) plugins.disable(plugin, onionr, stop_event = False) except Exception as e: logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin)) logger.debug(str(e))
def __event_caller(event_name, data = {}): ''' DO NOT call this function, this is for threading code only. Instead, call onionrevents.event ''' disabled = config.get('plugins.disabled') for plugin in plugins.get_enabled_plugins(): if plugin in disabled: continue try: call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(data)) except ModuleNotFoundError as e: logger.warn('Disabling nonexistant plugin "%s"...' % plugin, terminal=True) plugins.disable(plugin, stop_event = False) except Exception as e: logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin), terminal=True) logger.debug((event_name + ' - ' + plugin + ' - ' + str(e)), terminal=True)
def get_help_message(cmd: str, default: str = 'No help available for this command'): """Return help message for a given command, supports plugin commands""" pl_cmd = plugin_command(cmd) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, pl_cmd): try: return getattr(pl, pl_cmd).onionr_help except AttributeError: pass for i in arguments.get_arguments(): for alias in i: try: return arguments.get_help(cmd) except AttributeError: pass return default # Return the help string
def register(): """Registers commands and handles help command processing""" def get_help_message(cmd: str, default: str = 'No help available for this command'): """Return help message for a given command, supports plugin commands""" pl_cmd = plugin_command(cmd) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, pl_cmd): try: return getattr(pl, pl_cmd).onionr_help except AttributeError: pass for i in arguments.get_arguments(): for alias in i: try: return arguments.get_help(cmd) except AttributeError: pass return default # Return the help string PROGRAM_NAME = "onionr" # Get the command try: cmd = sys.argv[1] except IndexError: logger.debug("Detected Onionr run with no commands specified") return is_help_cmd = False if cmd.replace('--', '').lower() == 'help': is_help_cmd = True try: try: if not cmd in ('start', 'details', 'show-details'): os.chdir(os.environ['ORIG_ONIONR_RUN_DIR']) except KeyError: pass try: arguments.get_func(cmd)() except KeyboardInterrupt: pass except onionrexceptions.NotFound: if not register_plugin_commands(cmd) and not is_help_cmd: recommend.recommend() sys.exit(3) if is_help_cmd: try: sys.argv[2] except IndexError: for i in arguments.get_arguments(): logger.info( '%s <%s>: %s' % (PROGRAM_NAME, '/'.join(i), get_help_message(i[0])), terminal=True) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, 'ONIONR_COMMANDS'): print('') try: logger.info('%s commands:' % (pl.plugin_name, ), terminal=True) except AttributeError: logger.info('%s commands:' % (pl.__name__, ), terminal=True) for plugin_cmd in pl.ONIONR_COMMANDS: logger.info('%s %s: %s' % (PROGRAM_NAME, plugin_cmd, get_help_message(plugin_cmd)), terminal=True) print('') else: try: logger.info( '%s %s: %s' % (PROGRAM_NAME, sys.argv[2], get_help_message(sys.argv[2])), terminal=True) except KeyError: logger.error('%s: command does not exist.' % [sys.argv[2]], terminal=True) sys.exit(3) return
def register(): """Register commands and handles help command processing.""" def get_help_message(cmd: str, default: str = 'No help available for this command'): """Print help message for a given command, supports plugin commands.""" pl_cmd = plugin_command(cmd) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, pl_cmd): try: return getattr(pl, pl_cmd).onionr_help except AttributeError: pass for i in arguments.get_arguments(): for _ in i: try: return arguments.get_help(cmd) except AttributeError: pass return default # Return the help string PROGRAM_NAME = "onionr" # Get the command try: cmd = sys.argv[1] except IndexError: logger.info('Run with --help to see available commands', terminal=True) sys.exit(10) is_help_cmd = False if cmd.replace('--', '').lower() == 'help': is_help_cmd = True try: try: arguments.get_func(cmd)() except KeyboardInterrupt: pass except onionrexceptions.NotFound: if not register_plugin_commands(cmd) and not is_help_cmd: recommend.recommend() sys.exit(3) if is_help_cmd: try: sys.argv[2] except IndexError: for i in arguments.get_arguments(): _show_term('%s <%s>: %s' % (PROGRAM_NAME, '/'.join(i), get_help_message(i[0]))) for pl in onionrplugins.get_enabled_plugins(): pl = onionrplugins.get_plugin(pl) if hasattr(pl, 'ONIONR_COMMANDS'): print('') try: _show_term('%s commands:' % (pl.plugin_name, )) except AttributeError: _show_term('%s commands:' % (pl.__name__, )) for plugin_cmd in pl.ONIONR_COMMANDS: _show_term( '%s %s: %s' % (PROGRAM_NAME, plugin_cmd, get_help_message(plugin_cmd)), ) print('') else: try: _show_term( '%s %s: %s' % (PROGRAM_NAME, sys.argv[2], get_help_message(sys.argv[2]))) except KeyError: logger.error('%s: command does not exist.' % [sys.argv[2]], terminal=True) sys.exit(3) return
def __init__(self): ''' Main Onionr class. This is for the CLI program, and does not handle much of the logic. In general, external programs and plugins should not use this class. ''' try: os.chdir(sys.path[0]) except FileNotFoundError: pass # Load global configuration data data_exists = os.path.exists('data/') if not data_exists: os.mkdir('data/') 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({ 'devmode': True, 'log': { 'file': { 'output': True, 'path': 'data/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}})['console']['color']: settings = settings | logger.USE_ANSI if config.get('log', {'console': { 'output': True }})['console']['output']: settings = settings | logger.OUTPUT_TO_CONSOLE if config.get('log', {'file': {'output': True}})['file']['output']: settings = settings | logger.OUTPUT_TO_FILE logger.set_file( config.get('log', {'file': { 'path': 'data/output.log' }})['file']['path']) logger.set_settings(settings) if str(config.get('devmode', True)).lower() == 'true': self._developmentMode = True logger.set_level(logger.LEVEL_DEBUG) else: self._developmentMode = False logger.set_level(logger.LEVEL_INFO) self.onionrCore = core.Core() self.onionrUtils = OnionrUtils(self.onionrCore) # Handle commands self.debug = False # Whole application debugging if os.path.exists('data-encrypted.dat'): while True: print('Enter password to decrypt:') password = getpass.getpass() result = self.onionrCore.dataDirDecrypt(password) if os.path.exists('data/'): break else: logger.error('Failed to decrypt: ' + result[1], timestamp=False) else: # If data folder does not exist if not data_exists: if not os.path.exists('data/blocks/'): os.mkdir('data/blocks/') # Copy default plugins into plugins folder if not os.path.exists(plugins.get_plugins_folder()): if os.path.exists('static-data/default-plugins/'): names = [ f for f in os.listdir("static-data/default-plugins/") if not os.path.isfile(f) ] shutil.copytree('static-data/default-plugins/', plugins.get_plugins_folder()) # Enable plugins for name in names: if not name in plugins.get_enabled_plugins(): plugins.enable(name, self) for name in plugins.get_enabled_plugins(): if not os.path.exists(plugins.get_plugin_data_folder(name)): try: os.mkdir(plugins.get_plugin_data_folder(name)) except: plugins.disable(name, onionr=self, stop_event=False) if not os.path.exists(self.onionrCore.peerDB): self.onionrCore.createPeerDB() pass if not os.path.exists(self.onionrCore.addressDB): self.onionrCore.createAddressDB() # Get configuration if not data_exists: # Generate default config # Hostname should only be set if different from 127.x.x.x. Important for DNS rebinding attack prevention. if self.debug: randomPort = 8080 else: while True: randomPort = random.randint(1024, 65535) if self.onionrUtils.checkPort(randomPort): break config.set( 'client', { 'participate': 'true', 'client_hmac': base64.b16encode( os.urandom(32)).decode('utf-8'), 'port': randomPort, 'api_version': API_VERSION }, True) self.cmds = { '': self.showHelpSuggestion, 'help': self.showHelp, 'version': self.version, 'config': self.configure, 'start': self.start, 'stop': self.killDaemon, 'status': self.showStats, 'statistics': self.showStats, 'stats': self.showStats, 'enable-plugin': self.enablePlugin, 'enplugin': self.enablePlugin, 'enableplugin': self.enablePlugin, 'enmod': self.enablePlugin, 'disable-plugin': self.disablePlugin, 'displugin': self.disablePlugin, 'disableplugin': self.disablePlugin, 'dismod': self.disablePlugin, 'reload-plugin': self.reloadPlugin, 'reloadplugin': self.reloadPlugin, 'reload-plugins': self.reloadPlugin, 'reloadplugins': self.reloadPlugin, 'create-plugin': self.createPlugin, 'createplugin': self.createPlugin, 'plugin-create': self.createPlugin, 'listkeys': self.listKeys, 'list-keys': self.listKeys, 'addmsg': self.addMessage, 'addmessage': self.addMessage, 'add-msg': self.addMessage, 'add-message': self.addMessage, 'pm': self.sendEncrypt, 'getpms': self.getPMs, 'get-pms': self.getPMs, 'addpeer': self.addPeer, 'add-peer': self.addPeer, 'add-address': self.addAddress, 'add-addr': self.addAddress, 'addaddr': self.addAddress, 'addaddress': self.addAddress, 'addfile': self.addFile, 'importblocks': self.onionrUtils.importNewBlocks, 'introduce': self.onionrCore.introduceNode, 'connect': self.addAddress } self.cmdhelp = { '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', '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-msg': 'Broadcasts a message to the Onionr network', 'pm': 'Adds a private message to block', 'get-pms': 'Shows private messages sent to you', 'addfile': 'Create an Onionr block from a file', 'importblocks': 'import blocks from the disk (Onionr is transport-agnostic!)', 'introduce': 'Introduce your node to the public Onionr network', } # initialize plugins events.event('init', onionr=self, threaded=False) command = '' try: command = sys.argv[1].lower() except IndexError: command = '' finally: self.execute(command) if not self._developmentMode: encryptionPassword = self.onionrUtils.getPassword( 'Enter password to encrypt directory: ') self.onionrCore.dataDirEncrypt(encryptionPassword) shutil.rmtree('data/') return
def __init__(self): ''' Main Onionr class. This is for the CLI program, and does not handle much of the logic. In general, external programs and plugins should not use this class. ''' self.userRunDir = os.getcwd() # Directory user runs the program from self.killed = False if sys.argv[0] == os.path.basename(__file__): try: os.chdir(sys.path[0]) except FileNotFoundError: pass # set data dir self.dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/')) if not self.dataDir.endswith('/'): self.dataDir += '/' # set log file logger.set_file(os.environ.get('LOG_DIR', 'data') + '/onionr.log') # Load global configuration data data_exists = Onionr.setupConfig(self.dataDir, self) if netcontroller.torBinary() is None: logger.error('Tor is not installed') sys.exit(1) # If block data folder does not exist if not os.path.exists(self.dataDir + 'blocks/'): os.mkdir(self.dataDir + 'blocks/') # Copy default plugins into plugins folder if not os.path.exists(plugins.get_plugins_folder()): if os.path.exists('static-data/default-plugins/'): names = [f for f in os.listdir("static-data/default-plugins/")] shutil.copytree('static-data/default-plugins/', plugins.get_plugins_folder()) # Enable plugins for name in names: if not name in plugins.get_enabled_plugins(): plugins.enable(name, self) for name in plugins.get_enabled_plugins(): if not os.path.exists(plugins.get_plugin_data_folder(name)): try: os.mkdir(plugins.get_plugin_data_folder(name)) except: plugins.disable(name, onionr = self, stop_event = False) self.communicatorInst = None self.onionrCore = core.Core() self.onionrCore.onionrInst = self #self.deleteRunFiles() self.onionrUtils = onionrutils.OnionrUtils(self.onionrCore) self.clientAPIInst = '' # Client http api instance self.publicAPIInst = '' # Public http api instance signal.signal(signal.SIGTERM, self.exitSigterm) # Handle commands self.debug = False # Whole application debugging # Get configuration if type(config.get('client.webpassword')) is type(None): config.set('client.webpassword', base64.b16encode(os.urandom(32)).decode('utf-8'), savefile=True) if type(config.get('client.client.port')) is type(None): randomPort = netcontroller.getOpenPort() config.set('client.client.port', randomPort, savefile=True) if type(config.get('client.public.port')) is type(None): randomPort = netcontroller.getOpenPort() config.set('client.public.port', randomPort, savefile=True) if type(config.get('client.api_version')) is type(None): config.set('client.api_version', API_VERSION, savefile=True) self.cmds = commands.get_commands(self) self.cmdhelp = commands.cmd_help # initialize plugins events.event('init', onionr = self, threaded = False) command = '' try: command = sys.argv[1].lower() except IndexError: command = '' finally: self.execute(command) return