def init_prism(self): prism.init(self.flask_app, prism.settings.PRISM_CONFIG) # Load in prism's plugins logging.up('Starting plugin manager') prism.plugin_manager() logging.down()
def init(self): logging.up('Searching') self._search_plugins(settings.CORE_PLUGINS_PATH, True) self._search_plugins(settings.PLUGINS_PATH, False) logging.down() self._verify_dependencies() logging.up('Loading plugins') self._load_plugins() logging.down()
def ping_version(output=False): global PRISM_VERSIONING should_check = True if 'last_check' in PRISM_VERSIONING: should_check = ((datetime.now() - datetime.strptime(PRISM_VERSIONING['last_check'], "%Y-%m-%d %H:%M:%S")).seconds >= 60 * 60 * 2) if output or should_check: logging.up('Collecting version info...') if should_check: rate_limited, dev_changes, recent_releases, num_releases = get_new_versions(prism.__version__) if rate_limited: logging.error('Rate limited. Version info not checked.') # If no values made yet, apply some defaults if 'dev_changes' not in PRISM_VERSIONING: PRISM_VERSIONING['dev_changes'] = [] if 'recent_releases' not in PRISM_VERSIONING: PRISM_VERSIONING['recent_releases'] = [] if 'num_releases' not in PRISM_VERSIONING: PRISM_VERSIONING['num_releases'] = 0 else: # Reset and reapply cached versioning info PRISM_VERSIONING['dev_changes'] = [] PRISM_VERSIONING['recent_releases'] = [] PRISM_VERSIONING['num_releases'] = 0 if 'dev_changes' is not None: PRISM_VERSIONING['dev_changes'] = dev_changes if 'recent_releases' is not None: PRISM_VERSIONING['recent_releases'] = recent_releases if 'num_releases' is not None: PRISM_VERSIONING['num_releases'] = num_releases if 'dev_changes' is not None or 'recent_releases' is not None or 'num_releases' is not None: PRISM_VERSIONING['last_check'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") if output or should_check: if PRISM_VERSIONING['dev_changes'] is None: logging.error('Failed to check development version.') elif len(PRISM_VERSIONING['dev_changes']) > 0: logging.info('%s development commit(s) since the latest version.' % len(PRISM_VERSIONING['dev_changes'])) if PRISM_VERSIONING['recent_releases'] is None: logging.error('Failed to check for latest version.') elif len(PRISM_VERSIONING['recent_releases']) != 0: logging.info('Current version: %s' % prism.__version__) if prism.__version__ != PRISM_VERSIONING['recent_releases'][0]['name']: logging.error('Your version is out of date. Latest version is %s' % PRISM_VERSIONING['recent_releases'][0]['name']) logging.down() logging.down()
def start(self, opts): logging.output('----------=\e[1mPrism\e[0m=----------') prism.settings.init(os.getpid()) logging.up('Starting Prism') self.init_flask() self.jinja_options() self.init_flask_plugins() self.init_prism() prism.settings.post_init() self.start_http() return 0
def _verify_dependencies(self): # These will always be initialized. logging.up('Verifying dependencies') installed_packages_list = sorted( [i.key for i in pip.get_installed_distributions()]) for plugin_id, plugin_info in self.available_plugins.items(): if not plugin_info['_is_core']: if 'dependencies' not in plugin_info: continue if 'os' in plugin_info['dependencies']: if get_general_os() in plugin_info['dependencies']['os']: plugin_info['dependencies'] = data_merge( plugin_info['dependencies'], plugin_info['dependencies']['os'][ get_general_os()]) if 'plugin' in plugin_info['dependencies']: for depend_name in plugin_info['dependencies']['plugin']: installed = 'prism_' + depend_name in self.available_plugins if not installed: plugin_info['_is_satisfied'] = False plugin_info['_dependencies'].append( ('plugin', depend_name, installed)) if 'binary' in plugin_info['dependencies']: for depend_name in plugin_info['dependencies']['binary']: installed = is_package_installed(depend_name) if not installed: plugin_info['_is_satisfied'] = False plugin_info['_dependencies'].append( ('binary', depend_name, installed)) if 'module' in plugin_info['dependencies']: for depend_name in plugin_info['dependencies']['module']: installed = (depend_name in installed_packages_list) if not installed: plugin_info['_is_satisfied'] = False plugin_info['_dependencies'].append( ('module', depend_name, installed)) if not plugin_info['_is_satisfied']: # Create a dummy plugin container self._insert_dummy_plugin(plugin_info) logging.error('Dependency unsatisfied. Offender: %s' % plugin_id) logging.down()
def start_http(self): logging.output('Verifying SSL') has_ssl = False try: from OpenSSL import SSL has_ssl = True except ImportError: pass if has_ssl: ssl_crt = os.path.join(prism.settings.CONFIG_FOLDER, 'prism-ssl.crt') ssl_key = os.path.join(prism.settings.CONFIG_FOLDER, 'prism-ssl.key') ssl_files_exist = os.path.exists(ssl_crt) if ssl_files_exist: ssl_files_exist = os.path.exists(ssl_key) # Generate certificate if not ssl_files_exist: logging.up() logging.up('Generating SSL certificate') prism.settings.generate_certificate() logging.down() logging.down() if self.should_bind: # Finally, start Prism under a self-signed SSL connection self.flask_app.run(host='::', port=9000, threaded=True, debug=prism.settings.is_dev(), ssl_context=(ssl_crt, ssl_key)) else: if self.should_bind: logging.error( 'Warning: Prism is starting under an insecure connection!') self.flask_app.run(host='::', port=9000, threaded=True, debug=prism.settings.is_dev())
def _init_plugin(self, plugin): """ Initializes a plugin: 1. Runs the plugin's init() function. 2. Saves the config 3. Loads the plugin's endpoints into flask """ logging.up('Starting %s v%s' % (plugin.name, plugin.version)) def get_wrapper(plugin): def func(): return plugin return func setattr(plugin.__class__, 'get', get_wrapper(plugin)) plugin.init(PRISM_STATE) plugin.config.save() blueprint_name = plugin._endpoint # Create the plugin blueprint in flask plugin._blueprint = Blueprint(blueprint_name, plugin._info['_id'], template_folder='templates') if len(plugin._module_views) > 0: self.possible_permissions[plugin.plugin_id] = {} # Go through each of the module's views and add them to flask for view_class in plugin._module_views: view = view_class() self.possible_permissions[plugin.plugin_id][str( view_class.__name__)] = view.title endpoint_id = '%s' % view_class.__name__ with flask_app().app_context(): if view.menu is not None: # Generate the parent menu item if 'parent' in view.menu: if '.' not in view.menu['parent']['id']: parts = ('/' + blueprint_name + view.endpoint).split('/') flask_app().add_url_rule( '/'.join(parts[:-1]), endpoint=blueprint_name + '.' + view.menu['parent']['id']) item = current_menu.submenu( view.menu['parent']['id']) item.register(blueprint_name + '.' + view.menu['parent']['id'], view.menu['parent']['text'], view.menu['parent']['order'], icon=view.menu['parent']['icon']) else: item = current_menu.submenu( view.menu['parent']['id']) item.register(blueprint_name + '.' + endpoint_id, view.menu['parent']['text'], view.menu['parent']['order'], icon=view.menu['parent']['icon']) item = current_menu.submenu(view.menu['id']) item.register(blueprint_name + '.' + endpoint_id, view.title, view.menu['order'], icon=view.menu['icon']) if prism.settings.is_dev(): logging.info('Registered menu item for /%s: %s' % (blueprint_name + view.endpoint, view.menu['id'])) else: # Generate a hidden menu item so titles show correctly item = current_menu.submenu(generate_random_string(12)) item.register(blueprint_name + '.' + endpoint_id, view.title, hidden=True) # Find all methods in the view class for func_name in [ method for method in dir(view) if callable(getattr(view, method)) ]: if func_name.startswith('_'): continue if func_name not in ['get', 'post', 'put', 'delete']: if not func_name.endswith( ('_get', '_post', '_put', '_delete')): continue else: # Set the fallback http method to the extention of the function name parts = func_name.split('_') if parts[len(parts) - 1] in ('get', 'post', 'put', 'delete'): fallback_http_methods = [ parts[len(parts) - 1].upper() ] else: # Set the fallback http method to the function name fallback_http_methods = [func_name.upper()] if func_name == 'get': endpoint_id = '%s' % view_class.__name__ elif func_name.endswith('_get'): endpoint_id = '%s:%s' % (view_class.__name__, '_'.join( func_name.split('_')[:-1])) else: endpoint_id = '%s:%s' % (view_class.__name__, func_name) # Get the method func = getattr(view, func_name) view_func_wrapper = self.func_wrapper( plugin.plugin_id, func) # If the http methods have been specified in the @subroute decorator if hasattr(func, 'http_methods'): fallback_http_methods = func.http_methods fallback_endpoint = '/' # If an endpoint has been specified in the @subroute decorator if hasattr(func, 'endpoint'): fallback_endpoint = func.endpoint # Prepare fallback defaults for the page if hasattr(func, 'defaults'): fallback_defaults = func.defaults elif func.__defaults__ is not None: args, varargs, keywords, defaults = inspect.getargspec( func) fallback_defaults = dict( zip(args[-len(defaults):], defaults)) else: fallback_defaults = {} func_routes = list() if not hasattr(func, 'routes'): func_routes.append({ 'endpoint': fallback_endpoint, 'http_methods': fallback_http_methods, 'defaults': fallback_defaults }) else: func_routes = func.routes # Add a route for the get function with no parameters if func_name == 'get': plugin._blueprint.add_url_rule( view.endpoint + fallback_endpoint, endpoint=endpoint_id, methods=fallback_http_methods, view_func=view_func_wrapper, defaults=fallback_defaults) for route in func_routes: if 'endpoint' not in route: route['endpoint'] = fallback_endpoint if 'http_methods' not in route: route['http_methods'] = fallback_http_methods if 'defaults' not in route: route['defaults'] = fallback_defaults.copy() # Defaults are odd. They cannot be attached to routes with the key in the url # For example: if <id> in in the url rule, it cann't be in defaults. pattern = re.compile(r'<(?:.+?(?=:):)?(.+?)>') if '<' in route['endpoint'] and len( route['defaults']) > 0: for id in re.findall(pattern, route['endpoint']): try: del route['defaults'][id] except: pass if prism.settings.is_dev(): logging.info( 'Registered page /%s: %s %s' % (blueprint_name + view.endpoint + route['endpoint'], blueprint_name + '.' + endpoint_id, route['http_methods'])) plugin._blueprint.add_url_rule( view.endpoint + route['endpoint'], endpoint=endpoint_id, methods=route['http_methods'], view_func=view_func_wrapper, defaults=route['defaults']) flask_app().register_blueprint(plugin._blueprint, url_prefix='/' + blueprint_name.replace('.', '/')) plugin.post_init(PRISM_STATE) logging.down()
def _load_plugins(self): """ Attempts to load every enabled plugin """ plugins_loaded = list() core_plugins = list() plugins_additional = list() for plugin_id, plugin_info in self.available_plugins.items(): if plugin_info['_is_core']: core_plugins.append(plugin_info) elif plugin_info['_is_satisfied']: plugins_additional.append(plugin_info) # These will always be initialized. logging.info('Loading %s core plugin(s)' % len(core_plugins)) for plugin_info in core_plugins: plugin = self._import_plugin(plugin_info) if not plugin: logging.error( 'Error: Failed to load core plugin. Offender: %s' % plugin_info['id']) continue else: logging.good('Loaded %s' % plugin_info['id']) plugins_loaded.append(plugin) logging.down() logging.info('Sorting dependencies') sorted_plugins = [] while plugins_additional: added_any = False for plugin in plugins_additional: ready_add = True if 'dependencies' in plugin and 'plugin' in plugin[ 'dependencies']: for dependency in plugin['dependencies']['plugin']: found = False for ready_plugin in sorted_plugins: if ready_plugin['id'] == dependency: found = True break if not found: ready_add = False if ready_add: added_any = True sorted_plugins.append(plugin) plugins_additional.remove(plugin) if not added_any: break plugins_additional = sorted_plugins logging.up('Loading %s additional plugin(s)' % len(plugins_additional)) # Start plugins if they're set to be enabled. for plugin_info in plugins_additional: if not self.is_enabled(plugin_info['id']): self._insert_dummy_plugin(plugin_info) continue plugin = self._import_plugin(plugin_info) if not plugin: logging.error( 'Error: Failed to load additional plugin. Offender: %s' % plugin_id) continue else: logging.good('Loaded %s' % plugin_info['id']) plugins_loaded.append(plugin) logging.down() logging.up('Initializing %s plugin(s)' % len(plugins_loaded)) for plugin in plugins_loaded: plugin._info['_is_enabled'] = True self._init_plugin(plugin) logging.down()