def __init__(self, command=None, return_url=None, restart=False): self.command = command self.terminal_id = prism.generate_random_string(8) self.return_url = return_url self.restart = restart self.process = TerminalProcess(*pty.openpty()) logging.info('Terminal Opened: %s' % self.terminal_id)
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 _search_plugins(self, path, is_core): """ Searches for plugins in a specified folder """ if is_core: logging.info('Finding core plugins') else: logging.info('Finding additional plugins') sys.path.append(path) for plugin_id in os.listdir(path): if not plugin_id.startswith('prism_'): continue base_folder = os.path.join(path, plugin_id) if not os.path.isfile(base_folder): if not os.path.exists(os.path.join(base_folder, 'plugin.json')): logging.error( 'Plugin does not have a plugin.json file. Offender: %s' % plugin_id) continue plugin_info = JSONConfig(base_folder, 'plugin.json', auto_save=False) plugin_info['_id'] = plugin_id plugin_info['id'] = plugin_info['_id'].split('_', 1)[1] plugin_info['_is_core'] = is_core plugin_info['_is_satisfied'] = True plugin_info['_is_enabled'] = False # Make the version readable version = None for i in plugin_info['version']: if isinstance(i, int): if version is None: version = str(i) else: version += '.' + str(i) else: version += '-' + i plugin_info['_version'] = plugin_info['version'] plugin_info['version'] = version plugin_info['_dependencies'] = list() self.available_plugins[plugin_id] = plugin_info
def init(pid): global PANEL_PID, PRISM_PATH, TMP_PATH, PRISM_VERSIONING, CORE_PLUGINS_PATH, \ PLUGINS_PATH, CONFIG_FOLDER_PLUGINS, CONFIG_FOLDER, PRISM_CONFIG, PRISM_LOCALE PANEL_PID = pid PRISM_PATH = os.path.dirname(os.path.realpath(__file__)) CORE_PLUGINS_PATH = os.path.join(PRISM_PATH, 'core') if not os.path.exists(CORE_PLUGINS_PATH): os.makedirs(CORE_PLUGINS_PATH) PLUGINS_PATH = os.path.join(PRISM_PATH, 'plugins') if not os.path.exists(PLUGINS_PATH): os.makedirs(PLUGINS_PATH) TMP_PATH = os.path.join(PRISM_PATH, 'tmp') if not os.path.exists(TMP_PATH): os.makedirs(TMP_PATH) logging.info('Currently running in %s' % PRISM_PATH) logging.output() PRISM_VERSIONING = JSONConfig(path=os.path.join(TMP_PATH, 'VERSIONING-INFO')) # Load Prism's config CONFIG_FOLDER = os.path.join(PRISM_PATH, 'config') if not os.path.exists(CONFIG_FOLDER): os.makedirs(CONFIG_FOLDER) config_file = os.path.join(CONFIG_FOLDER, 'config.json') CONFIG_FOLDER_PLUGINS = os.path.join(CONFIG_FOLDER, 'plugins') if not os.path.exists(CONFIG_FOLDER_PLUGINS): os.makedirs(CONFIG_FOLDER_PLUGINS) PRISM_LOCALE = LocaleConfig(PRISM_PATH) # Generate default config values if the file doesn't exist # Also, prompt and generate a few of the config values that # must be done on first run. if not os.path.exists(config_file): # I have no idea what came over me when making this section, # but it's fabulous and I loved every second of it. I hope # I never have to change it. xD logging.output(PRISM_LOCALE['start.hello.1']) logging.output(PRISM_LOCALE['start.hello.2']) subst = {} # IP Address/Hostname prompt subst['host'] = socket.gethostbyname(socket.gethostname()) logging.output(PRISM_LOCALE['start.host'].format(**subst)) PRISM_CONFIG['host'], used_default = prism.get_input(PRISM_LOCALE['start.host.prompt'], default=subst['host']) if used_default: logging.output() logging.output(PRISM_LOCALE['start.host.correct']) # Secret generation logging.output() logging.output(PRISM_LOCALE['start.secret']) subst['secret_key'], used_default = prism.get_input(PRISM_LOCALE['start.secret.prompt']) logging.output() if used_default: subst['secret_key'] = prism.generate_random_string(32) logging.output(PRISM_LOCALE['start.secret.generate'].format(**subst)) else: logging.output(PRISM_LOCALE['start.secret.done'].format(**subst)) PRISM_CONFIG['secret_key'] = subst['secret_key'] # Dev check logging.output() logging.output(PRISM_LOCALE['start.dev_mode']) PRISM_CONFIG['dev_mode'] = prism.get_yesno(PRISM_LOCALE['start.dev_mode.prompt']) logging.output() logging.output(PRISM_LOCALE['start.done']) logging.output() conf = JSONConfig(path=config_file) for key, value in PRISM_CONFIG.items(): conf[key] = value PRISM_CONFIG = conf else: # Load prism's config PRISM_CONFIG = JSONConfig(path=config_file) if 'locale' not in PRISM_CONFIG: PRISM_CONFIG['locale'] = 'en_US' if 'enabled_plugins' not in PRISM_CONFIG: PRISM_CONFIG['enabled_plugins'] = [F] # Make sure some VERY imporant values are set if 'secret_key' not in PRISM_CONFIG: logging.output(PRISM_LOCALE['start.missing.secret']) PRISM_CONFIG['secret_key'] = prism.generate_random_string(32) logging.output() if 'host' not in PRISM_CONFIG: host = socket.gethostbyname(socket.gethostname()) logging.output(PRISM_LOCALE['start.missing.host']) PRISM_CONFIG['host'], used_default = prism.get_input(PRISM_LOCALE['start.host.prompt'], default=host) logging.output()
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()