def on_webhook(self, path, request): """ Serves the current configuration """ if not self.ready: return "Plugin not ready" if request.method == "GET": if path == "/" or not path: return render_template_string(INDEX) elif path == "get-config": # send configuration return json.dumps(self.config, default=serializer) else: abort(404) elif request.method == "POST": if path == "save-config": try: save_config(request.get_json(), '/etc/pwnagotchi/config.toml') # test _thread.start_new_thread(restart, (self.mode, )) return "success" except Exception as ex: logging.error('[webcfg] %s', ex) return "config error", 500 abort(404)
def toggle_plugin(name, enable=True): """ Load or unload a plugin returns True if changed, otherwise False """ import pwnagotchi from pwnagotchi.ui import view from pwnagotchi.utils import save_config global loaded, database if pwnagotchi.config: pwnagotchi.config['main']['plugins'][name]['enabled'] = enable save_config(pwnagotchi.config, '/etc/pwnagotchi/config.toml') if not enable and name in loaded: if getattr(loaded[name], 'on_unload', None): loaded[name].on_unload(view.ROOT) del loaded[name] return True if enable and name in database and name not in loaded: load_from_file(database[name]) one(name, 'loaded') if pwnagotchi.config: one(name, 'config_changed', pwnagotchi.config) one(name, 'ui_setup', view.ROOT) one(name, 'ready', view.ROOT._agent) return True return False
def edit(args, config): """ Edit the config of the plugin """ plugin = args.name editor = os.environ.get('EDITOR', 'vim') # because vim is the best if plugin not in config['main']['plugins']: return 1 plugin_config = {'main': {'plugins': {plugin: config['main']['plugins'][plugin]}}} import toml from subprocess import call from tempfile import NamedTemporaryFile from pwnagotchi.utils import DottedTomlEncoder new_plugin_config = None with NamedTemporaryFile(suffix=".tmp", mode='r+t') as tmp: tmp.write(toml.dumps(plugin_config, encoder=DottedTomlEncoder())) tmp.flush() rc = call([editor, tmp.name]) if rc != 0: return rc tmp.seek(0) new_plugin_config = toml.load(tmp) config['main']['plugins'][plugin] = new_plugin_config['main']['plugins'][plugin] save_config(config, args.user_config) return 0
def disable(args, config): """ Disables the given plugin and saves the config to disk """ if args.name not in config['main']['plugins']: config['main']['plugins'][args.name] = dict() config['main']['plugins'][args.name]['enabled'] = False save_config(config, args.user_config) return 0
def install(args, config): """ Installs the given plugin """ global DEFAULT_INSTALL_PATH plugin_name = args.name available = _get_available() installed = _get_installed(config) if plugin_name not in available: logging.error('%s not found.', plugin_name) return 1 if plugin_name in installed: logging.error('%s already installed.', plugin_name) # install into custom_plugins path install_path = config['main']['custom_plugins'] if not install_path: install_path = DEFAULT_INSTALL_PATH config['main']['custom_plugins'] = install_path save_config(config, args.user_config) os.makedirs(install_path, exist_ok=True) shutil.copyfile( available[plugin_name], os.path.join(install_path, os.path.basename(available[plugin_name]))) # maybe has config for conf in glob.glob(available[plugin_name].replace('.py', '.y?ml')): dst = os.path.join(install_path, os.path.basename(conf)) if os.path.exists(dst) and md5(dst) != md5(conf): # backup logging.info('Backing up config: %s', os.path.basename(conf)) shutil.move(dst, dst + '.bak') shutil.copyfile(conf, dst) return 0
def edit(args, config): """ Edit the config of the plugin """ plugin = args.name editor = os.environ.get('EDITOR', 'vim') # because vim is the best installed = _get_installed(config) if plugin not in config['main']['plugins'] and plugin not in installed: return 1 defaults = dict() if plugin in installed: data = analyze_plugin(installed[plugin]) defaults = data['__defaults__'] if '__defaults__' in data else dict() plugin_config = {'main': {'plugins': {plugin: merge_config(config['main']['plugins'][plugin], defaults)}}} import toml from subprocess import call from tempfile import NamedTemporaryFile from pwnagotchi.utils import DottedTomlEncoder new_plugin_config = None with NamedTemporaryFile(suffix=".tmp", mode='r+t') as tmp: tmp.write(toml.dumps(plugin_config, encoder=DottedTomlEncoder())) tmp.flush() rc = call([editor, tmp.name]) if rc != 0: return rc tmp.seek(0) new_plugin_config = toml.load(tmp) config['main']['plugins'][plugin] = new_plugin_config['main']['plugins'][plugin] save_config(config, args.user_config) return 0
def install(args, config): """ Installs the given plugin """ global DEFAULT_INSTALL_PATH plugin_name = args.name available = _get_available() installed = _get_installed(config) if plugin_name not in available: logging.error('%s not found.', plugin_name) return 1 if plugin_name in installed: logging.error('%s already installed.', plugin_name) # install into custom_plugins path install_path = config['main']['custom_plugins'] if not install_path: install_path = DEFAULT_INSTALL_PATH config['main']['custom_plugins'] = install_path save_config(config, args.user_config) plugin_info = analyze_plugin(available[plugin_name]) if '__min_pwnagotchi_version__' in plugin_info: min_version = parse_version(plugin_info['__min_pwnagotchi_version__']) pwn_version = parse_version(pwnagotchi_version) if pwn_version < min_version: looging.error("Can't install %s because it requires pwnagotchi version %s", plugin_name, min_version) return 1 if '__dependencies__' in plugin_info: deps = plugin_info['__dependencies__'] if 'pip' in deps: for d in deps['pip']: if not pip_install(d): logging.error('Dependency "%s" not found', d) return 1 if 'apt' in deps: for d in deps['apt']: if not apt_install(d): logging.error('Dependency "%s" not found', d) return 1 os.makedirs(install_path, exist_ok=True) if '__assets__' in plugin_info: assets = plugin_info['__assets__'] if assets: if not isinstance(assets, list): assets = [assets] for a in assets: if a.startswith('https://'): dst = os.path.join(install_path, os.path.basename(a)) if not os.path.exists(dst) and not has_internet(): logging.error('Could not download asset %s', a) return 1 logging.info('Downloading asset: %s', os.path.basename(a)) download_file(a, dst) continue for f in glob.glob(a): dst = os.path.join(install_path, os.path.basename(f)) logging.info('Copy asset: %s', os.path.basename(f)) shutil.copyfile(f, dst) shutil.copyfile(available[plugin_name], os.path.join(install_path, os.path.basename(available[plugin_name]))) return 0