Example #1
0
def list_plugins(args, config, pattern='*'):
    """
    Lists the available and installed plugins
    """
    found = False

    line = "|{name:^{width}}|{version:^9}|{enabled:^10}|{status:^15}|"

    available = _get_available()
    installed = _get_installed(config)

    available_and_installed = set(list(available.keys()) + list(installed.keys()))
    available_not_installed = set(available.keys()) - set(installed.keys())

    max_len = max(map(len, available_and_installed))
    header = line.format(name='Plugin', width=max_len, version='Version', enabled='Active', status='Status')
    line_length = max(max_len, len('Plugin')) + len(header) - len('Plugin') - 12

    print('-' * line_length)
    print(header)
    print('-' * line_length)

    # only installed (maybe update available?)
    for plugin, filename in sorted(installed.items()):
        if not fnmatch(plugin, pattern):
            continue
        found = True
        plugin_info = analyze_plugin(filename)
        installed_version = parse_version(plugin_info['__version__'])
        available_version = None
        if plugin in available:
            available_plugin_info = analyze_plugin(available[plugin])
            available_version = parse_version(available_plugin_info['__version__'])

        status = "installed"
        if installed_version and available_version:
            if available_version > installed_version:
                status = "installed (^)"

        enabled = 'enabled' if plugin in config['main']['plugins'] and \
                  'enabled' in config['main']['plugins'][plugin] and \
                  config['main']['plugins'][plugin]['enabled'] \
                  else 'disabled'

        print(line.format(name=plugin, width=max_len, version='.'.join(installed_version), enabled=enabled, status=status))

    for plugin in sorted(available_not_installed):
        if not fnmatch(plugin, pattern):
            continue
        found = True
        available_plugin_info = analyze_plugin(available[plugin])
        available_version = available_plugin_info['__version__']
        print(line.format(name=plugin, width=max_len, version=available_version, enabled='-', status='available'))

    print('-' * line_length)

    if not found:
        logging.info('Maybe try: pwnagotchi plugins update')
        return 1
    return 0
Example #2
0
def uninstall(args, config):
    """
    Uninstalls a plugin
    """
    plugin_name = args.name
    installed = _get_installed(config)
    if plugin_name not in installed:
        logging.error('Plugin %s is not installed.', plugin_name)
        return 1

    plugin_info = analyze_plugin(installed[plugin_name])

    if '__assets__' in plugin_info:
        assets = plugin_info['__assets__']
        if assets:
            if not isinstance(assets, list):
                assets = [assets]

            for a in assets:
                for f in glob.glob(a):
                    logging.info('Delete asset: %s', os.path.basename(f))
                    os.remove(f)

    os.remove(installed[plugin_name])
    # but keep config

    return 0
Example #3
0
def load_from_path(path, enabled=list()):
    global loaded, database
    logging.debug("loading plugins from %s - enabled: %s" % (path, enabled))
    for filename in glob.glob(os.path.join(path, "*.py")):
        plugin_name = os.path.basename(filename.replace(".py", ""))
        if plugin_name == 'example':
            continue
        database[plugin_name] = analyze_plugin(filename)
        if plugin_name in enabled:
            try:
                load_from_file(filename)
            except Exception as e:
                logging.warning("error while loading %s: %s" % (filename, e))
                logging.debug(e, exc_info=True)

    return loaded
Example #4
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
Example #5
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
Example #6
0
def upgrade(args, config, pattern='*'):
    """
    Upgrades the given plugin
    """
    available = _get_available()
    installed = _get_installed(config)

    for plugin, filename in installed.items():
        if not fnmatch(plugin, pattern) or plugin not in available:
            continue

        available_plugin_data = analyze_plugin(available[plugin])
        available_version = parse_version(available_plugin_data['__version__'])
        installed_version = parse_version(analyze_plugin(filename)['__version__'])

        if installed_version and available_version:
            if available_version <= installed_version:
                continue
        else:
            continue

        if '__min_pwnagotchi_version__' in available_plugin_data:
            min_version = parse_version(available_plugin_data['__min_pwnagotchi_version__'])
            pwn_version = parse_version(pwnagotchi_version)
            if pwn_version < min_version:
                looging.info('Skip %s because it requires pwnagotchi version %s', plugin, min_version)
                continue

        logging.info('Upgrade %s from %s to %s', plugin, '.'.join(installed_version), '.'.join(available_version))

        if '__dependencies__' in available_plugin_data:
            deps = available_plugin_data['__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

        if '__assets__' in available_plugin_data:
            assets = available_plugin_data['__assets__']
            if assets:
                if not isinstance(assets, list):
                    assets = [assets]

                for a in assets:
                    if a.startswith('https://'):
                        dst = os.path.join(os.path.dirname(installed[plugin]), 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(os.path.dirname(installed[plugin]), os.path.basename(f))
                        logging.info('Copy asset: %s', os.path.basename(f))
                        shutil.copyfile(f, dst)

        shutil.copyfile(available[plugin], installed[plugin])

    return 0
Example #7
0
def list_plugins(args, config, pattern='*'):
    """
    Lists the available and installed plugins
    """
    from rich.console import Console
    from rich.table import Table

    console = Console()

    table = Table(show_header=True, header_style="bold")

    table.add_column("Name")
    table.add_column("Version")
    table.add_column("Enabled")
    table.add_column("Status")

    found = False

    available = _get_available()
    installed = _get_installed(config)

    available_not_installed = set(available.keys()) - set(installed.keys())

    # only installed (maybe update available?)
    for plugin, filename in sorted(installed.items()):
        if not fnmatch(plugin, pattern):
            continue
        found = True
        plugin_info = analyze_plugin(filename)
        installed_version = parse_version(plugin_info['__version__'])
        available_version = None
        if plugin in available:
            available_plugin_info = analyze_plugin(available[plugin])
            available_version = parse_version(available_plugin_info['__version__'])

        status = "installed"
        if installed_version and available_version:
            if available_version > installed_version:
                status = "installed (^)"

        enabled = 'enabled' if plugin in config['main']['plugins'] and \
                  'enabled' in config['main']['plugins'][plugin] and \
                  config['main']['plugins'][plugin]['enabled'] \
                  else 'disabled'

        table.add_row(plugin, '.'.join(installed_version), enabled, status)

    for plugin in sorted(available_not_installed):
        if not fnmatch(plugin, pattern):
            continue
        found = True
        available_plugin_info = analyze_plugin(available[plugin])
        available_version = available_plugin_info['__version__']
        table.add_row(plugin, available_version, '-', 'available')

    if not found:
        logging.info('Maybe try: pwnagotchi plugins update')
        return 1

    console.print(table)

    return 0