def main():
    # Create some history first. (Easy for testing.)
    history = InMemoryHistory()
    history.append_string('import os')
    history.append_string('print("hello")')
    history.append_string('print("world")')
    history.append_string('import path')

    # Print help.
    print('This CLI has fish-style auto-suggestion enable.')
    print('Type for instance "pri", then you\'ll see a suggestion.')
    print('Press the right arrow to insert the suggestion.')
    print('Press Control-C to retry. Control-D to exit.')
    print()

    session = PromptSession(
        history=history,
        auto_suggest=AutoSuggestFromHistory(),
        enable_history_search=True)

    while True:
        try:
            text = session.prompt('Say something: ')
        except KeyboardInterrupt:
            pass  # Ctrl-C pressed. Try again.
        else:
            break

    print('You said: %s' % text)
Beispiel #2
0
Datei: cli.py Projekt: pilona/RPN
 def __iter__(self):
     try:
         session = PromptSession(message=self.prompt,
                                 vi_mode=True,
                                 enable_suspend=True,
                                 enable_open_in_editor=True,
                                 # Persistent
                                 history=None,  # TODO
                                 # Stack size? Top of stack?
                                 rprompt=None,  # TODO
                                 # TODO:
                                 # - Stack size?
                                 # - Editing mode?
                                 # - I/O format, rounding?
                                 # - Hints? Help?
                                 # - Truncated stack?
                                 bottom_toolbar=None,  # TODO
                                 prompt_continuation=' ' * len(self.prompt),
                                 # Debatable. Interferes with X11 selection.
                                 mouse_support=True,
                                 # Certainly not! But be explicit.
                                 erase_when_done=False)
         # TODO: colour, lexing, completion
         while True:
             yield session.prompt()
     except EOFError:
         return
def main():
    # Create some history first. (Easy for testing.)
    history = InMemoryHistory()
    history.append_string('import os')
    history.append_string('print("hello")')
    history.append_string('print("world")')
    history.append_string('import path')

    # Print help.
    print('This CLI has up-arrow partial string matching enabled.')
    print('Type for instance "pri" followed by up-arrow and you')
    print('get the last items starting with "pri".')
    print('Press Control-C to retry. Control-D to exit.')
    print()

    session = PromptSession(history=history, enable_history_search=True)

    while True:
        try:
            text = session.prompt('Say something: ')
        except KeyboardInterrupt:
            pass  # Ctrl-C pressed. Try again.
        else:
            break

    print('You said: %s' % text)
Beispiel #4
0
    def run_cli(self):
        # get catalog data before start
        self.refresher.refresh(self.executor, self.completer, [])
        # Load history into completer so it can learn user preferences
        history = FileHistory(os.path.expanduser('~/.voltsql_history'))
        self.completer.init_prioritization_from_history(history)

        session = PromptSession(
            lexer=PygmentsLexer(SqlLexer), completer=self.completer, style=style,
            auto_suggest=AutoSuggestFromHistory(), bottom_toolbar=self.bottom_toolbar,
            key_bindings=self.create_key_bindings(), multiline=True,
            history=history)

        # directly assign multiline=False in PromptSession constructor will cause some unexpected behavior
        # due to some issue i don't know. This is a workaround.
        if not self.multiline:
            session.default_buffer.multiline = ~session.default_buffer.multiline

        option_str = "--servers={server} --port={port_number}{user}{password}{credentials}" \
                     "{ssl}{output_format}{output_skip_metadata}{stop_on_error}{kerberos} " \
                     "--query-timeout={number_of_milliseconds}".format(
            server=self.server, port_number=self.port,
            user="******" + self.user if self.user else "",
            password="******" + self.password if self.password else "",
            credentials=" --credentials=" + self.credentials if self.credentials else "",
            kerberos=" --kerberos=" + self.kerberos if self.kerberos else "",
            number_of_milliseconds=self.query_timeout,
            ssl=" --ssl=" + self.ssl_set if self.ssl_set else " --ssl" if self.ssl else "",
            output_format=" --output-format=" + self.output_format if self.output_format else "",
            output_skip_metadata=" --output-skip-metadata" if self.output_skip_metadata else "",
            stop_on_error=" --stop-on-error=false" if not self.stop_on_error else ""
        )
        while True:
            try:
                sql_cmd = session.prompt('> ')
            except KeyboardInterrupt:
                break
            except EOFError:
                break
            else:
                if sql_cmd.lower() == "refresh":
                    # use "refresh" command to force a fresh
                    self.refresher.refresh(self.executor, self.completer, [])
                    continue
                if sql_cmd.strip().lower() in ("quit", "quit;", "exit", "exit;"):
                    # exit
                    break
                if sql_cmd.strip().lower() in ("help", "help;"):
                    print(README)
                    continue
                call(
                    "echo \"{sql_cmd}\" | sqlcmd {options}".format(
                        sql_cmd=sql_cmd, options=option_str),
                    shell=True)
                if self.auto_refresh:
                    self.refresher.refresh(self.executor, self.completer, [])
        print('GoodBye!')
def main():
    our_history = FileHistory('.example-history-file')

    # The history needs to be passed to the `PromptSession`. It can't be passed
    # to the `prompt` call because only one history can be used during a
    # session.
    session = PromptSession(history=our_history)

    while True:
        text = session.prompt('Say something: ')
        print('You said: %s' % text)
def main():
    print(
        'Asynchronous loading of history. Notice that the up-arrow will work '
        'for as far as the completions are loaded.\n'
        'Even when the input is accepted, loading will continue in the '
        'background and when the next prompt is displayed.\n'
    )
    our_history = ThreadedHistory(SlowHistory())

    # The history needs to be passed to the `PromptSession`. It can't be passed
    # to the `prompt` call because only one history can be used during a
    # session.
    session = PromptSession(history=our_history)

    while True:
        text = session.prompt('Say something: ')
        print('You said: %s' % text)
def main(database):
    connection = sqlite3.connect(database)
    session = PromptSession(
        lexer=PygmentsLexer(SqlLexer), completer=sql_completer, style=style)

    while True:
        try:
            text = session.prompt('> ')
        except KeyboardInterrupt:
            continue  # Control-C pressed. Try again.
        except EOFError:
            break  # Control-D pressed.

        with connection:
            try:
                messages = connection.execute(text)
            except Exception as e:
                print(repr(e))
            else:
                for message in messages:
                    print(message)

    print('GoodBye!')
Beispiel #8
0
    def __init__(self):
        self.name = 'main'
        self.prompt_session = PromptSession(
            'ST ≫ ',
            bottom_toolbar=bottom_toolbar,
            auto_suggest=AutoSuggestFromHistory(),
            enable_history_search=True,
            # rprompt=get_rprompt,
            # style=rprompt_style
        )

        self.contexts = [
            Listeners(self.prompt_session),
            Sessions(self.prompt_session),
            Modules(self.prompt_session),
            Stagers(self.prompt_session)
        ]

        self.prompt_session.completer = WordCompleter([ctx.name for ctx in self.contexts] + ['exit'], ignore_case=True)
        self.prompt_session.contexts = self.contexts

        self.current_context = self
class TUI:
    def __init__(self):
        self.core = Core()
        self.session = PromptSession(reserve_space_for_menu=7)
        self.tableData = None
        self.table = None
        self.cfSlugs = None
        self.wowiSlugs = None
        self.completer = None
        self.os = platform.system()
        if self.os == 'Windows':
            self.chandle = windll.kernel32.GetStdHandle(-11)
        sys.tracebacklimit = 0

    def start(self):
        self.setup_console()
        self.print_header()
        # Check if executable is in good location
        if not glob.glob('World*.app') and not glob.glob('Wow*.exe') or \
                not os.path.isdir(Path('Interface/AddOns')) or not os.path.isdir('WTF'):
            printft(
                HTML(
                    '<ansibrightred>This executable should be placed in the same directory where Wow.exe, '
                    'WowClassic.exe or World of Warcraft.app is located.</ansibrightred>\n'
                ))
            pause()
            sys.exit(1)
        # Detect Classic client
        if os.path.basename(os.getcwd()) == '_classic_':
            self.core.clientType = 'wow_classic'
            set_terminal_title(f'CurseBreaker v{__version__} - Classic')
        # Check if client have write access
        try:
            with open('PermissionTest', 'w') as _:
                pass
            os.remove('PermissionTest')
        except IOError:
            printft(
                HTML(
                    '<ansibrightred>CurseBreaker doesn\'t have write rights for the current directory.\n'
                    'Try starting it with administrative privileges.</ansibrightred>\n'
                ))
            pause()
            sys.exit(1)
        self.auto_update()
        self.core.init_config()
        self.setup_table()
        # Curse URI Support
        if len(sys.argv) == 2 and 'twitch://' in sys.argv[1]:
            try:
                self.c_install(sys.argv[1].strip())
            except Exception as e:
                self.handle_exception(e)
            timeout()
            sys.exit(0)
        if len(sys.argv) == 2 and '.ccip' in sys.argv[1]:
            try:
                path = sys.argv[1].strip()
                self.c_install(self.core.parse_cf_xml(path))
                if os.path.exists(path):
                    os.remove(path)
            except Exception as e:
                self.handle_exception(e)
            timeout()
            sys.exit(0)
        # CLI command
        if len(sys.argv) >= 2:
            command = ' '.join(sys.argv[1:]).split(' ', 1)
            if getattr(self, f'c_{command[0].lower()}', False):
                try:
                    getattr(self, f'c_{command[0].lower()}')(
                        command[1].strip() if len(command) > 1 else False)
                except Exception as e:
                    self.handle_exception(e)
            else:
                printft('Command not found.')
            sys.exit(0)
        # Addons auto update
        if len(self.core.config['Addons']) > 0:
            printft('Automatic update of all addons will start in 5 seconds.\n'
                    'Press any button to enter interactive mode.')
            starttime = time.time()
            keypress = None
            while True:
                if kbhit():
                    keypress = getch()
                    break
                elif time.time() - starttime > 5:
                    break
            if not keypress:
                if len(self.core.config['Addons']) > 35:
                    self.setup_console(len(self.core.config['Addons']))
                self.print_header()
                try:
                    self.c_update(None, True)
                    if self.core.backup_check():
                        self.setup_table()
                        printft(
                            HTML(
                                '\n<ansigreen>Backing up WTF directory:</ansigreen>'
                            ))
                        self.core.backup_wtf()
                    if self.core.config['WAUsername'] != 'DISABLED':
                        self.setup_table()
                        self.c_wa_update(None, False)
                except Exception as e:
                    self.handle_exception(e)
                printft('')
                pause()
                sys.exit(0)
        self.setup_completer()
        self.setup_console(len(self.core.config['Addons']))
        self.print_header()
        printft(
            HTML(
                'Use command <ansigreen>help</ansigreen> or press <ansigreen>TAB</ansigreen> to see a list of avai'
                'lable commands.\nCommand <ansigreen>exit</ansigreen> or pressing <ansigreen>CTRL+D</ansigreen> wi'
                'll close the application.\n'))
        if len(self.core.config['Addons']) == 0:
            printft(
                HTML(
                    'Command <ansigreen>import</ansigreen> might be used to detect already installed addons.\n'
                ))
        # Prompt session
        while True:
            try:
                command = self.session.prompt(
                    HTML('<ansibrightgreen>CB></ansibrightgreen> '),
                    completer=self.completer)
            except KeyboardInterrupt:
                continue
            except EOFError:
                break
            else:
                command = command.split(' ', 1)
                if getattr(self, f'c_{command[0].lower()}', False):
                    try:
                        self.setup_table()
                        getattr(self, f'c_{command[0].lower()}')(
                            command[1].strip() if len(command) > 1 else False)
                        self.setup_completer()
                    except Exception as e:
                        self.handle_exception(e)
                else:
                    printft('Command not found.')

    def auto_update(self):
        if getattr(sys, 'frozen', False):
            try:
                if os.path.isfile(sys.executable + '.old'):
                    try:
                        os.remove(sys.executable + '.old')
                    except PermissionError:
                        pass
                payload = requests.get(
                    'https://api.github.com/repos/AcidWeb/CurseBreaker/releases/latest',
                    headers=HEADERS).json()
                remoteversion = payload['name']
                changelog = payload['body']
                url = None
                for binary in payload['assets']:
                    if (self.os == 'Windows' and '.exe' in binary['name'])\
                            or (self.os == 'Darwin' and '.zip' in binary['name'])\
                            or (self.os == 'Linux' and '.gz' in binary['name']):
                        url = binary['browser_download_url']
                        break
                if url and StrictVersion(
                        remoteversion[1:]) > StrictVersion(__version__):
                    printft(
                        HTML(
                            '<ansigreen>Updating CurseBreaker...</ansigreen>'))
                    shutil.move(sys.executable, sys.executable + '.old')
                    payload = requests.get(url, headers=HEADERS)
                    if self.os == 'Darwin':
                        zipfile.ZipFile(io.BytesIO(
                            payload.content)).extractall()
                    else:
                        with open(sys.executable, 'wb') as f:
                            if self.os == 'Windows':
                                f.write(payload.content)
                            elif self.os == 'Linux':
                                f.write(gzip.decompress(payload.content))
                    os.chmod(sys.executable, 0o775)
                    printft(
                        HTML(
                            f'<ansibrightgreen>Update complete! Please restart the application.</ansibrightgreen'
                            f'>\n\n<ansigreen>Changelog:</ansigreen>\n{changelog}\n'
                        ))
                    pause()
                    sys.exit(0)
            except Exception as e:
                printft(
                    HTML(
                        f'<ansibrightred>Update failed!\n\nReason: {str(e)}</ansibrightred>\n'
                    ))
                pause()
                sys.exit(1)

    def handle_exception(self, e, table=True):
        if len(self.tableData) > 1 and table:
            self.sanitize_table()
            printft(ANSI(self.table.table))
        if getattr(sys, 'frozen', False):
            if isinstance(e, list):
                for es in e:
                    printft(
                        HTML(f'\n<ansibrightred>{str(es)}</ansibrightred>'))
            else:
                printft(HTML(f'\n<ansibrightred>{str(e)}</ansibrightred>'))
        else:
            if isinstance(e, list):
                for es in e:
                    traceback.print_exception(es,
                                              es,
                                              es.__traceback__,
                                              limit=1000)
            else:
                traceback.print_exc(limit=1000)

    def print_header(self):
        clear()
        printft(
            HTML(
                f'<ansibrightblack>~~~ <ansibrightgreen>CurseBreaker</ansibrightgreen> <ansibrightred>v'
                f'{__version__}</ansibrightred> ~~~</ansibrightblack>\n'))

    def setup_console(self, buffer=0):
        if getattr(sys, 'frozen', False) and self.os == 'Windows':
            if buffer > 0:
                windll.kernel32.SetConsoleScreenBufferSize(
                    self.chandle, wintypes._COORD(100,
                                                  100 + round(buffer, -2)))
            else:
                windll.kernel32.SetConsoleWindowInfo(
                    self.chandle, True,
                    byref(wintypes.SMALL_RECT(0, 0, 99, 49)))
                windll.kernel32.SetConsoleScreenBufferSize(
                    self.chandle, wintypes._COORD(100, 50))
        elif self.os == 'Darwin':
            set_terminal_size(100, 50)

    def setup_completer(self):
        if not self.cfSlugs or not self.wowiSlugs:
            # noinspection PyBroadException
            try:
                self.cfSlugs = pickle.load(
                    gzip.open(
                        io.BytesIO(
                            requests.get(
                                'https://storage.googleapis.com/cursebreaker/cfslugs.pickle.gz',
                                headers=HEADERS).content)))
                self.wowiSlugs = pickle.load(
                    gzip.open(
                        io.BytesIO(
                            requests.get(
                                'https://storage.googleapis.com/cursebreaker/wowislugs.pickle.gz',
                                headers=HEADERS).content)))
            except Exception:
                self.cfSlugs = []
                self.wowiSlugs = []
        commands = [
            'install', 'uninstall', 'update', 'force_update', 'wa_update',
            'status', 'orphans', 'search', 'import', 'export', 'toggle_backup',
            'toggle_dev', 'toggle_wa', 'set_wa_api', 'set_wa_wow_account',
            'uri_integration', 'help', 'exit'
        ]
        addons = sorted(self.core.config['Addons'],
                        key=lambda k: k['Name'].lower())
        for addon in addons:
            name = f'"{addon["Name"]}"' if ',' in addon["Name"] else addon[
                "Name"]
            commands.extend([
                f'uninstall {name}', f'update {name}', f'force_update {name}',
                f'toggle_dev {name}', f'status {name}'
            ])
        for item in self.cfSlugs:
            commands.append(f'install cf:{item}')
        for item in self.wowiSlugs:
            commands.append(f'install wowi:{item}')
        commands.extend(
            ['install ElvUI', 'install ElvUI:Dev', 'install Tukui'])
        wa = WeakAuraUpdater('', '', '')
        accounts = wa.get_accounts()
        for account in accounts:
            commands.append(f'set_wa_wow_account {account}')
        self.completer = WordCompleter(commands,
                                       ignore_case=True,
                                       sentence=True)

    def setup_table(self):
        self.tableData = [[
            f'{AC.LIGHTWHITE_EX}Status{AC.RESET}',
            f'{AC.LIGHTWHITE_EX}Name{AC.RESET}',
            f'{AC.LIGHTWHITE_EX}Version{AC.RESET}'
        ]]
        self.table = SingleTable(
            self.tableData) if self.os == 'Windows' else UnicodeSingleTable(
                self.tableData)
        self.table.justify_columns[0] = 'center'

    def sanitize_table(self):
        if not self.table.ok:
            mwidth = self.table.column_max_width(1)
            for row in self.table.table_data[1:]:
                if len(row[1]) > mwidth:
                    row[1] = row[1][:mwidth - 3] + '...'

    def c_install(self, args):
        if args:
            if args.startswith('-i '):
                args = args[3:]
                optignore = True
            else:
                optignore = False
            addons = [
                addon.strip()
                for addon in list(reader([args], skipinitialspace=True))[0]
            ]
            with tqdm(total=len(addons),
                      bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar:
                for addon in addons:
                    installed, name, version = self.core.add_addon(
                        addon, optignore)
                    if installed:
                        self.tableData.append(
                            [f'{AC.GREEN}Installed{AC.RESET}', name, version])
                    else:
                        self.tableData.append([
                            f'{AC.LIGHTBLACK_EX}Already installed{AC.RESET}',
                            name, version
                        ])
                    pbar.update(1)
            self.sanitize_table()
            printft(ANSI(self.table.table))
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links as an a'
                    'rgument.\n\tOption <ansiwhite>-i</ansiwhite> will disable the client version check.\n<ansigre'
                    'en>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com/wow/addons/[addon_name] <ansiwhi'
                    'te>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/[addon_name] <ansi'
                    'white>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=[addon_id] <ansiwh'
                    'ite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php?id=[addon_id] <an'
                    'siwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvU'
                    'I:Dev\n\tTukui'))

    def c_uninstall(self, args):
        if args:
            addons = [
                addon.strip()
                for addon in list(reader([args], skipinitialspace=True))[0]
            ]
            with tqdm(total=len(addons),
                      bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar:
                for addon in addons:
                    name, version = self.core.del_addon(addon)
                    if name:
                        self.tableData.append([
                            f'{AC.LIGHTRED_EX}Uninstalled{AC.RESET}', name,
                            version
                        ])
                    else:
                        self.tableData.append([
                            f'{AC.LIGHTBLACK_EX}Not installed{AC.RESET}',
                            addon, ''
                        ])
                    pbar.update(1)
            self.sanitize_table()
            printft(ANSI(self.table.table))
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links as an a'
                    'rgument.\n<ansigreen>Supported URLs:</ansigreen>\n\thttps://www.curseforge.com/wow/addons/[ad'
                    'don_name] <ansiwhite>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/'
                    '[addon_name] <ansiwhite>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id='
                    '[addon_id] <ansiwhite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php'
                    '?id=[addon_id] <ansiwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvU'
                    'I:Dev\n\tTukui'))

    def c_update(self, args, addline=False, update=True, force=False):
        if len(self.core.cfCache) > 0 or len(self.core.wowiCache) > 0:
            self.core.cfCache = {}
            self.core.wowiCache = {}
        if args:
            addons = [
                addon.strip()
                for addon in list(reader([args], skipinitialspace=True))[0]
            ]
        else:
            addons = sorted(self.core.config['Addons'],
                            key=lambda k: k['Name'].lower())
            self.core.bulk_check(addons)
        with tqdm(total=len(addons),
                  bar_format='{n_fmt}/{total_fmt} |{bar}|') as pbar:
            exceptions = []
            for addon in addons:
                try:
                    name, versionnew, versionold, modified = self.core.\
                        update_addon(addon if isinstance(addon, str) else addon['URL'], update, force)
                    if versionold:
                        if versionold == versionnew:
                            if modified:
                                self.tableData.append([
                                    f'{AC.LIGHTRED_EX}Modified{AC.RESET}',
                                    name, versionold
                                ])
                            else:
                                self.tableData.append([
                                    f'{AC.GREEN}Up-to-date{AC.RESET}', name,
                                    versionold
                                ])
                        else:
                            if modified:
                                self.tableData.append([
                                    f'{AC.LIGHTRED_EX}Update suppressed{AC.RESET}',
                                    name, versionold
                                ])
                            else:
                                self.tableData.append([
                                    f'{AC.YELLOW}{"Updated " if update else "Update available"}'
                                    f'{AC.RESET}', name,
                                    f'{AC.YELLOW}{versionnew}{AC.RESET}'
                                ])
                    else:
                        self.tableData.append([
                            f'{AC.LIGHTBLACK_EX}Not installed{AC.RESET}',
                            addon, ''
                        ])
                except Exception as e:
                    exceptions.append(e)
                pbar.update(1)
        self.sanitize_table()
        printft(ANSI('\n' + self.table.table if addline else self.table.table))
        if len(exceptions) > 0:
            self.handle_exception(exceptions, False)

    def c_force_update(self, args):
        if args:
            self.c_update(args, False, True, True)
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a comma-separated list of links or addo'
                    'n names as an argument.'))

    def c_status(self, args):
        self.c_update(args, False, False)

    def c_orphans(self, _):
        orphansd, orphansf = self.core.find_orphans()
        printft(
            HTML(
                '<ansigreen>Directories that are not part of any installed addon:</ansigreen>'
            ))
        for orphan in sorted(orphansd):
            printft(
                HTML(orphan.replace('[GIT]',
                                    '<ansiyellow>[GIT]</ansiyellow>')))
        printft(
            HTML(
                '\n<ansigreen>Files that are leftovers after no longer installed addons:</ansigreen>'
            ))
        for orphan in sorted(orphansf):
            printft(orphan)

    def c_uri_integration(self, _):
        if self.os == 'Windows':
            self.core.create_reg()
            printft(
                'CurseBreaker.reg file was created. Attempting to import...')
            out = os.system('"' + str(
                Path(os.path.dirname(sys.executable), 'CurseBreaker.reg')) +
                            '"')
            if out != 0:
                printft(
                    'Import failed. Please try to import REG file manually.')
            else:
                os.remove('CurseBreaker.reg')
        else:
            printft('This feature is available only on Windows.')

    def c_symlink_protection(self, _):
        if self.os == 'Windows':
            printft(HTML('<ansigreen>Directories tweaked:</ansigreen>'))
            for root, dirs, _ in os.walk(self.core.path / '..' / '..'):
                for d in dirs:
                    path = Path(root) / d
                    if os.path.islink(path):
                        set_icon(path, Path("C:/Windows/System32/SHELL32.dll"),
                                 4)
                        print(path.resolve())
        else:
            printft('This feature is available only on Windows.')

    def c_toggle_dev(self, args):
        if args:
            status = self.core.dev_toggle(args)
            if status is None:
                printft(
                    HTML(
                        '<ansibrightred>This addon does not exist or it is not installed yet.</ansibrightred>'
                    ))
            elif status:
                printft('This addon will now prioritize alpha/beta versions.')
            else:
                printft(
                    'This addon will not longer prioritize alpha/beta versions.'
                )
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts an addon name as an argument.'
                ))

    def c_toggle_backup(self, _):
        status = self.core.backup_toggle()
        printft(
            'Backup of WTF directory is now:',
            HTML('<ansigreen>ENABLED</ansigreen>')
            if status else HTML('<ansired>DISABLED</ansired>'))

    def c_toggle_wa(self, args):
        if args:
            if args == self.core.config['WAUsername']:
                printft(
                    HTML(
                        f'WeakAuras version check is now: <ansigreen>ENABLED</ansigreen>\n'
                        f'Auras created by <ansiwhite>{self.core.config["WAUsername"]}</ansiwhite>'
                        f' are now included.'))
                self.core.config['WAUsername'] = ''
            else:
                self.core.config['WAUsername'] = args.strip()
                printft(
                    HTML(
                        f'WeakAuras version check is now: <ansigreen>ENABLED</ansigreen>\n'
                        f'Auras created by <ansiwhite>{self.core.config["WAUsername"]}</ansiwhite>'
                        f' are now ignored.'))
        else:
            if self.core.config['WAUsername'] == 'DISABLED':
                self.core.config['WAUsername'] = ''
                printft(
                    HTML(
                        'WeakAuras version check is now: <ansigreen>ENABLED</ansigreen>'
                    ))
            else:
                self.core.config['WAUsername'] = '******'
                shutil.rmtree(Path('Interface/AddOns/WeakAurasCompanion'),
                              ignore_errors=True)
                printft(
                    HTML(
                        'WeakAuras version check is now: <ansired>DISABLED</ansired>'
                    ))
        self.core.save_config()

    def c_set_wa_api(self, args):
        if args:
            printft('Wago API key is now set.')
            self.core.config['WAAPIKey'] = args.strip()
            self.core.save_config()
        elif self.core.config['WAAPIKey'] != '':
            printft('Wago API key is now removed.')
            self.core.config['WAAPIKey'] = ''
            self.core.save_config()
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts API key as an argument.'
                ))

    def c_set_wa_wow_account(self, args):
        if args:
            args = args.strip()
            if os.path.isfile(
                    Path(f'WTF/Account/{args}/SavedVariables/WeakAuras.lua')):
                printft(
                    HTML(
                        f'WoW account name set to: <ansiwhite>{args}</ansiwhite>'
                    ))
                self.core.config['WAAccountName'] = args
                self.core.save_config()
            else:
                printft('Incorrect WoW account name.')
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts the WoW account name as an argument.'
                ))

    def c_wa_update(self, _, verbose=True):
        if os.path.isdir(Path('Interface/AddOns/WeakAuras')):
            wa = WeakAuraUpdater(
                '' if self.core.config['WAUsername'] == 'DISABLED' else
                self.core.config['WAUsername'],
                self.core.config['WAAccountName'],
                self.core.config['WAAPIKey'])
            accounts = wa.get_accounts()
            if len(accounts) > 1:
                if verbose:
                    printft(
                        HTML(
                            'More than one WoW account detected.\nPlease use <ansiwhite>set_wa_wow_account</ansiwh'
                            'ite> command to set the correct account name.'))
                else:
                    printft(
                        HTML(
                            '\n<ansigreen>More than one WoW account detected.</ansigreen>\nPlease use <ansiwhite>s'
                            'et_wa_wow_account</ansiwhite> command to set the correct account name.'
                        ))
                return
            if wa.accountName:
                if not self.core.config['WAAccountName']:
                    self.core.config['WAAccountName'] = wa.accountName
                    self.core.save_config()
                if self.core.waCompanionVersion != self.core.config[
                        'WACompanionVersion']:
                    self.core.config[
                        'WACompanionVersion'] = self.core.waCompanionVersion
                    self.core.save_config()
                    force = True
                else:
                    force = False
                wa.parse_storage()
                status = wa.check_updates()
                wa.install_companion(self.core.clientType, force)
                wa.install_data()
                if verbose:
                    printft(HTML('<ansigreen>Outdated WeakAuras:</ansigreen>'))
                    for aura in status[0]:
                        printft(aura)
                    printft(
                        HTML('\n<ansigreen>Detected WeakAuras:</ansigreen>'))
                    for aura in status[1]:
                        printft(aura)
                else:
                    printft(
                        HTML(
                            f'\n<ansigreen>The number of outdated WeakAuras:</ansigreen> {len(status[0])}'
                        ))
        elif verbose:
            printft('WeakAuras addon is not installed.')

    def c_search(self, args):
        if args:
            results = self.core.search(args)
            printft(HTML('<ansigreen>Top results of your search:</ansigreen>'))
            for url in results:
                if self.core.check_if_installed(url):
                    printft(
                        HTML(f'{url} <ansiyellow>[Installed]</ansiyellow>'))
                else:
                    printft(url)
        else:
            printft(
                HTML(
                    '<ansigreen>Usage:</ansigreen>\n\tThis command accepts a search query as an argument.'
                ))

    def c_import(self, args):
        hit, partial_hit, miss = self.core.detect_addons()
        if args == 'install' and len(hit) > 0:
            self.c_install(','.join(hit))
        else:
            printft(HTML(f'<ansigreen>Addons found:</ansigreen>'))
            for addon in hit:
                printft(addon)
            printft(HTML(f'\n<ansiyellow>Possible matches:</ansiyellow>'))
            for addon in partial_hit:
                printft(HTML(' <ansiwhite>or</ansiwhite> '.join(addon)))
            printft(HTML(f'\n<ansired>Unknown directories:</ansired>'))
            for addon in miss:
                printft(f'{addon}')
            printft(
                HTML(
                    f'\nExecute <ansiwhite>import install</ansiwhite> command to install all detected addons.\n'
                    f'Possible matches need to be installed manually with the <ansiwhite>install</ansiwhite>'
                    f' command.'))

    def c_export(self, _):
        printft(self.core.export_addons())

    def c_help(self, _):
        printft(
            HTML(
                '<ansigreen>install [URL]</ansigreen>\n\tCommand accepts a comma-separated list of links.\n'
                '<ansigreen>uninstall [URL/Name]</ansigreen>\n\tCommand accepts a comma-separated list of links or'
                ' addon names.\n'
                '<ansigreen>update [URL/Name]</ansigreen>\n\tCommand accepts a comma-separated list of links or ad'
                'don names.\n\tIf no argument is provided all non-modified addons will be updated.\n'
                '<ansigreen>force_update [URL/Name]</ansigreen>\n\tCommand accepts a comma-separated list of links'
                ' or addon names.\n\tSelected addons will be reinstalled or updated regardless of their current st'
                'ate.\n'
                '<ansigreen>wa_update</ansigreen>\n\tCommand detects all installed WeakAuras and generate WeakAura'
                's Companion payload.\n'
                '<ansigreen>status</ansigreen>\n\tPrints the current state of all installed addons.\n'
                '<ansigreen>orphans</ansigreen>\n\tPrints list of orphaned directories and files.\n'
                '<ansigreen>search [Keyword]</ansigreen>\n\tExecutes addon search on CurseForge.\n'
                '<ansigreen>import</ansigreen>\n\tCommand attempts to import already installed addons.\n'
                '<ansigreen>export</ansigreen>\n\tCommand prints list of all installed addons in a form suitable f'
                'or sharing.\n'
                '<ansigreen>toggle_backup</ansigreen>\n\tEnables/disables automatic daily backup of WTF directory.'
                '\n<ansigreen>toggle_dev [Name]</ansigreen>\n\tCommand accepts an addon name as argument.\n\tPrior'
                'itizes alpha/beta versions for the provided addon.\n'
                '<ansigreen>toggle_wa [Username]</ansigreen>\n\tEnables/disables automatic WeakAuras updates.\n\tI'
                'f a username is provided check will start to ignore the specified author.\n'
                '<ansigreen>set_wa_api [API key]</ansigreen>\n\tSets Wago API key required to access private auras'
                '.\n\tIt can be procured here: https://wago.io/account\n'
                '<ansigreen>set_wa_wow_account [Account name]</ansigreen>\n\tSets WoW account used by WeakAuras up'
                'dater.\n\tNeeded only if WeakAuras are used on more than one WoW account.\n'
                '<ansigreen>uri_integration</ansigreen>\n\tEnables integration with CurseForge page. "Install" but'
                'ton will now start this application.\n'
                '\n<ansibrightgreen>Supported URL:</ansibrightgreen>\n\thttps://www.curseforge.com/wow/addons/[add'
                'on_name] <ansiwhite>|</ansiwhite> cf:[addon_name]\n\thttps://www.wowinterface.com/downloads/[addo'
                'n_name] <ansiwhite>|</ansiwhite> wowi:[addon_id]\n\thttps://www.tukui.org/addons.php?id=[addon_id'
                '] <ansiwhite>|</ansiwhite> tu:[addon_id]\n\thttps://www.tukui.org/classic-addons.php?id=[addon_id'
                '] <ansiwhite>|</ansiwhite> tuc:[addon_id]\n\tElvUI <ansiwhite>|</ansiwhite> ElvUI:Dev\n\tTukui'
            ))

    def c_exit(self, _):
        sys.exit(0)
Beispiel #10
0
class ActionParser:
    def __init__(self):
        self.player_actions = {"debug": [["toggle_debug"]]}
        self.custom_actions = {}
        self.game = None
        self.session = PromptSession()
        self.events = {}
        self.global_vars = {}

        self.action_parsers = {
            "verify": run_verify_action,
            "for_each_concept": run_foreach_action,
            "search_for_concept": run_search_for_concept_action,
            "calc": run_calc_action
        }

    def add_custom_action(self, action_name, actions):
        printme("ActionParser:add_player_action - action_name: " + action_name,
                debug=True)
        self.custom_actions[action_name] = actions

    def add_player_action(self, action_name, actions):
        printme("ActionParser:add_player_action - action_name: " + action_name,
                debug=True)
        self.player_actions[action_name] = actions

    def parse_contextual_arg(self, arg, action_name, parent_args):

        if (action_name != "verify" and
                action_name != "for_each_concept") and arg.__class__ == list:
            arg = self.run_actions(arg, parent_args)

        if arg.__class__ == str:
            for global_var in self.global_vars:
                arg = arg.replace("#" + str(global_var) + "#",
                                  str(self.global_vars[global_var]))
            if parent_args.__class__ == dict:
                for key in parent_args:
                    arg = arg.replace("#" + key + "#", parent_args[key])
            elif parent_args.__class__ == list:
                for index, arg_value in enumerate(parent_args):
                    arg_index = "#arg" + str(index + 1) + "#"
                    printme("attempt to replace %s in %s with data %s " %
                            (arg_index, arg, arg_value),
                            debug=True)
                    if arg == arg_index:
                        arg = arg_value
                        break
                    else:
                        arg = arg.replace(arg_index, str(arg_value))
            if arg.__class__ == str and "#" in arg:
                arg = self.parse_concept_inside_string(arg)
        return arg

    def run_action(self, action_name, data=None, parent_args=None):
        printme("running action: %s with data %s and parent args: %s" %
                (action_name, data, parent_args),
                debug=True)

        if data is not None:
            new_data = []
            for arg in data:
                arg = self.parse_contextual_arg(arg, action_name, parent_args)
                printme("final arg: %s" % (arg, ), debug=True)
                new_data.append(arg)
            data = new_data

        if action_name == "get_player_command_action":
            return self.session.prompt(">> ")
        elif action_name == "print":
            print_msg = ""

            for print_arg in data:
                msg = print_arg
                if msg.__class__ == list:
                    msg = self.run_action(msg[0], msg[1:], parent_args)
                print_msg += str(msg)

            printme(print_msg)
        elif action_name == "exit":
            sys.exit()
        elif action_name == "save":
            with open(data[0], 'w') as f:
                json.dump(self.game, f)
        elif action_name == "get_concept":
            current_concept = self.get_concept(data[0])

            printme("Returns concept %s" % (current_concept, ), debug=True)

            return current_concept
        elif action_name == "get_concept_list":
            current_concept_list = self.get_concept(data[0])

            if current_concept_list.__class__ == dict:
                current_concept_list = list(current_concept_list.keys())

            printme("Returns concept list %s" % (current_concept_list, ),
                    debug=True)

            return current_concept_list
        elif action_name == "set_concept":
            self.set_concept(data[0], data[1:])
        elif action_name == "remove_concept":
            target_keywords = data[0].split("/")

            current_concept = self.game

            for keyword in target_keywords[:-1]:
                if keyword not in current_concept:
                    # Create a subconcept
                    current_concept[keyword] = {}
                current_concept = current_concept[keyword]

            if current_concept.__class__ == list:
                current_concept.remove(target_keywords[-1])
            else:
                current_concept.pop(target_keywords[-1])
        elif action_name == "grammar":
            grammar = SimpleGrammar()

            target_grammar = data[0]
            if target_grammar.__class__ == list:
                target_grammar = target_grammar[0]
            printme("loading grammar: %s" % (target_grammar, ), debug=True)

            text = grammar.parse(target_grammar)

            printme("grammar generated text: %s" % (text, ), debug=True)

            return text
        elif action_name == "run":
            target_actions = data[0]
            if target_actions.__class__ == str:
                target_actions = ast.literal_eval(target_actions)
            return self.run_actions(target_actions, parent_args)
        elif action_name == "return":
            return data[0]
        elif action_name == "instantiate":
            target_concept = self.get_concept(data[0])
            store_concept = data[1]

            new_concept_name = data[0].split("/")[-1] + ("instance_%4d" %
                                                         (randint(0, 9999), ))
            new_concept = store_concept + "/" + new_concept_name

            self.global_vars["LAST_INSTANTIATE_ENTITY"] = new_concept

            self.set_concept(new_concept, target_concept)

        elif action_name == "propagate_event":
            self.propagate_event(data[0])
        elif action_name in self.custom_actions:
            self.run_actions(self.custom_actions[action_name], data)
        elif action_name == "toggle_debug":
            metagame.utils.printme.show_debug = not metagame.utils.printme.show_debug
        elif action_name in self.action_parsers:
            return self.action_parsers[action_name](self, data, parent_args)
        else:
            if "#" in action_name:
                action_name = self.parse_contextual_arg(
                    action_name, "", parent_args)
            possible_concept = self.get_concept(action_name)
            if possible_concept and possible_concept.__class__ == list:
                concept_path = action_name.strip().split("/")
                if len(concept_path) > 1:
                    concept_path = concept_path[:-1]
                    root_concept = "/".join(concept_path)
                    printme("root concept: " + str(root_concept), debug=True)
                    self.global_vars["SELF"] = root_concept
                action_value = self.run_actions(possible_concept, data)
                self.global_vars["SELF"] = None
                return action_value
            else:
                return str([action_name] + data)

    def run_actions(self, actions, args=None):
        if actions is None:
            return

        if len(actions) > 0 and actions[0].__class__ == list:
            for action in actions[:-1]:
                self.run_action(action[0], action[1:], args)
            return self.run_action(actions[-1][0], actions[-1][1:], args)
        else:
            return self.run_action(actions[0], actions[1:], args)

    def actions_matches(self, player_action, registered_action):
        words_player_action = player_action.strip().split(" ")
        words_registered_action = registered_action.strip().split(" ")

        if len(words_registered_action) != len(words_player_action):
            return False

        for action, register in zip(words_player_action,
                                    words_registered_action):
            printme("actions_matches: %s - %s" % (action, register),
                    debug=True)
            if action != register and not register.isupper():
                printme("actions_matches: %s - %s - return False" %
                        (action, register),
                        debug=True)
                return False

        printme("actions_matches: %s - %s - return True" %
                (player_action, registered_action),
                debug=True)
        return True

    def parse_actions_args(self, player_action, registered_action):
        words_player_action = player_action.strip().split(" ")
        words_registered_action = registered_action.strip().split(" ")

        dict_arg = {}

        for action, register in zip(words_player_action,
                                    words_registered_action):
            if register.isupper():
                dict_arg[register] = action

        return dict_arg

    def run_player_action(self, player_action):
        # player_cmds = player_action.split(" ")

        # action_name = player_cmds[0]

        if player_action == "help":
            printme("The following commands are available:")
            for action in self.game["game"]["available_actions"]:
                printme("- %s" % (action, ))
            for action in self.player_actions:
                printme("- %s" % (action, ))
        else:
            for action in self.player_actions:
                if self.actions_matches(player_action, action):
                    self.run_actions(
                        self.player_actions[action],
                        self.parse_actions_args(player_action, action))

    def parse_concept_inside_string(self, arg):
        target_concepts = []

        current_concept = ""
        inside_concept = False

        for s in arg:
            if not inside_concept:
                if current_concept == "" and s == '#':
                    inside_concept = True
            else:
                if s == '#':
                    target_concepts.append(current_concept)
                    current_concept = ""
                    inside_concept = False
                else:
                    current_concept += s

        for concept in target_concepts:
            printme("attempt to replace concept inside string: %s" %
                    (concept, ),
                    debug=True)
            arg = arg.replace("#" + concept + "#",
                              str(self.get_concept(concept)))

        return arg

    def set_concept(self, concept_name, concept_value):
        target_keywords = concept_name.split("/")
        target_value = concept_value
        if concept_value.__class__ == list:
            if len(concept_value) > 2:
                # concept meaning will be a list
                target_value = concept_value[1:]
            else:
                target_value = concept_value[0]
        else:
            target_value = concept_value

        current_concept = self.game

        for keyword in target_keywords[:-1]:
            if is_integer(keyword):
                keynumber = int(keyword) - 1
                if current_concept.__class__ == list:
                    current_concept = current_concept[keynumber]
                else:
                    keys_list = list(current_concept.keys())
                    current_concept = current_concept[keys_list[keynumber]]
            else:
                if keyword not in current_concept:
                    # Create a subconcept
                    current_concept[keyword] = {}
                current_concept = current_concept[keyword]

        current_concept[target_keywords[-1]] = target_value

    def get_concept(self, concept_name, verify=False):
        target_keywords = concept_name.split("/")
        current_concept = self.game

        if verify:
            last_concept = target_keywords[-1]
            target_keywords = target_keywords[:-1]

        try:
            for keyword in target_keywords:
                if is_integer(keyword):
                    keynumber = int(keyword) - 1
                    if current_concept.__class__ == list:
                        current_concept = current_concept[keynumber]
                    else:
                        keys_list = list(current_concept.keys())
                        current_concept = current_concept[keys_list[keynumber]]
                else:
                    current_concept = current_concept[keyword]
        except:
            return False

        if verify:
            if current_concept is None:
                return False
            if is_integer(last_concept):
                keynumber = int(last_concept) - 1
                if current_concept.__class__ == list:
                    return current_concept[keynumber]
                else:
                    keys_list = list(current_concept.keys())
                    return current_concept[keys_list[keynumber]]
            return last_concept in current_concept

        return current_concept

    def register_event(self, event_name):
        if event_name not in self.events:
            self.events[event_name] = {"subscribers": []}

    def propagate_event(self, event_name):
        if event_name in self.game:
            self.run_actions(self.game[event_name])
        if event_name in self.events:
            for subscriber in self.events[event_name]["subscribers"]:
                if subscriber in self.game:
                    subscriber_concept = self.game[subscriber]
                    if 'event_subscriber' in subscriber_concept:
                        if event_name in subscriber_concept[
                                "event_subscriber"]:
                            event_response = subscriber_concept[
                                "event_subscriber"][event_name]
                            if 'actions' in event_response:
                                self.run_actions(event_response["actions"])

    def register_event_subscriber(self, event, concept):
        if event in self.events:
            self.events[event]["subscribers"].append(concept)
        else:
            self.events[event] = {"subscribers": [concept]}
Beispiel #11
0
class CommandPrompt(object):
    def __init__(self) -> None:
        self.commands = self.get_commands()
        self.cmd_handler = CommandHandler(self.commands)
        self.completer = CommandCompleter(self.commands)
        self.style = self.get_style()
        self._break = False
        self.prompt_session = PromptSession(
            completer=self.completer,
            style=self.style,
            bottom_toolbar=self.bottom_toolbar,
            auto_suggest=AutoSuggestFromHistory())
        super(CommandPrompt, self).__init__()

    # --------------------------------------------------------------- #

    def get_commands(self):
        return COMMANDS

    # --------------------------------------------------------------- #

    def get_prompt(self):
        return HTML('<b>> </b>')

    # --------------------------------------------------------------- #

    def get_style(self):
        Style.from_dict({
            'completion-menu.completion': 'bg:#008888 #ffffff',
            'completion-menu.completion.current': 'bg:#00aaaa #000000',
            'scrollbar.background': 'bg:#88aaaa',
            'scrollbar.button': 'bg:#222222',
            'token.literal.string.single': '#98ff75'
        })

    # --------------------------------------------------------------- #

    def intro_message(self):
        print_formatted_text(HTML('<b>Starting prompt...</b>'))

    # --------------------------------------------------------------- #

    def exit_message(self):
        print_formatted_text(HTML('<b>Exiting prompt...</b>'))

    # --------------------------------------------------------------- #

    def handle_exit(self, tokens: list) -> None:
        if len(tokens) > 0:
            if tokens[0] in ('exit', 'quit', 'q'):
                # TODO: exit gracefully
                sys.exit(0)

    # --------------------------------------------------------------- #

    def handle_break(self, tokens: list) -> bool:
        if tokens[0] in ('c', 'continue'):
            return True
        else:
            return False

    # --------------------------------------------------------------- #

    def handle_command(self, tokens: list) -> None:
        if len(tokens) > 0:
            self.cmd_handler.handle_command(tokens)

    # --------------------------------------------------------------- #

    def bottom_toolbar(self):
        return None

    # --------------------------------------------------------------- #

    def start_prompt(self) -> None:
        self.intro_message()
        while True:
            try:
                cmd = self.prompt_session.prompt(self.get_prompt, )

                tokens = get_tokens(cmd)

                if not self.handle_break(tokens):
                    self.handle_exit(tokens)
                    self.handle_command(tokens)

            except KeyboardInterrupt:
                continue
            except EOFError:
                # self.handle_exit(['exit'])
                break
        self.exit_message()
Beispiel #12
0
    def __init__(self, project=None, extra_locals=None):
        """
        Launch the Brownie console.

        Arguments
        ---------
        project : `Project`, optional
            Active Brownie project to include in the console's local namespace.
        extra_locals: dict, optional
            Additional variables to add to the console namespace.
        """
        console_settings = CONFIG.settings["console"]

        locals_dict = dict((i, getattr(brownie, i)) for i in brownie.__all__)
        locals_dict.update(
            _dir=dir, dir=self._dir, exit=_Quitter("exit"), quit=_Quitter("quit"), _console=self
        )

        if project:
            project._update_and_register(locals_dict)

        # only make GUI available if Tkinter is installed
        try:
            Gui = importlib.import_module("brownie._gui").Gui
            locals_dict["Gui"] = Gui
        except ModuleNotFoundError:
            pass

        if extra_locals:
            locals_dict.update(extra_locals)

        # create prompt session object
        history_file = str(_get_data_folder().joinpath(".history").absolute())
        kwargs = {}
        if console_settings["show_colors"]:
            kwargs.update(
                lexer=PygmentsLexer(PythonLexer),
                style=style_from_pygments_cls(get_style_by_name(console_settings["color_style"])),
                include_default_pygments_style=False,
            )
        if console_settings["auto_suggest"]:
            kwargs["auto_suggest"] = ConsoleAutoSuggest(self, locals_dict)
        if console_settings["completions"]:
            kwargs["completer"] = ConsoleCompleter(self, locals_dict)
        if console_settings["editing_mode"]:
            kwargs["editing_mode"] = EditingMode(console_settings["editing_mode"].upper())

        self.compile_mode = "single"
        self.prompt_session = PromptSession(
            history=SanitizedFileHistory(history_file, locals_dict),
            input=self.prompt_input,
            key_bindings=KeyBindings(),
            **kwargs,
        )

        # add custom bindings
        key_bindings = self.prompt_session.key_bindings
        key_bindings.add(Keys.BracketedPaste)(self.paste_event)

        key_bindings.add("c-i")(self.tab_event)
        key_bindings.get_bindings_for_keys(("c-i",))[-1].filter = lambda: not self.tab_filter()

        # modify default bindings
        key_bindings = load_key_bindings()
        key_bindings.get_bindings_for_keys(("c-i",))[-1].filter = self.tab_filter

        if console_settings["auto_suggest"]:
            # remove the builtin binding for auto-suggest acceptance
            key_bindings = self.prompt_session.app.key_bindings
            accept_binding = key_bindings.get_bindings_for_keys(("right",))[0]
            key_bindings._bindings2.remove(accept_binding.handler)

        # this is required because of a pytest conflict when using the debugging console
        if sys.platform == "win32":
            import colorama

            colorama.init()

        super().__init__(locals_dict)
Beispiel #13
0
class Console:
    def __init__(self):
        self.prompt = u"$ "
        self.banner = ""
        self.session = PromptSession(history=FileHistory('/tmp/history.txt'))
        self.error_prompt = u"*** "
        self.info_prompt = u"[+] "
        self.commands = sorted([
            func[3:] for func in dir(self)
            if func[0:3] == "do_" and callable(getattr(self, func))
        ])
        self.doced_commands = [
            func for func in self.commands if "help_" +
            func in dir(self) and callable(getattr(self, "help_" + func))
        ]
        self.undoced_commands = list(
            set(self.commands).difference(set(self.doced_commands)))

    def do_test(self, arg):
        print("This is test function")
        print(repr(self))
        print(arg)

    def do_help(self, arg):
        if not arg:
            print("Help Manual")
            if self.doced_commands:
                print("Documented commands(type help <topic>):")
                print("=" * 25)
                for each in self.doced_commands:
                    print(each + "\t")
            if self.undoced_commands:
                if self.doced_commands:
                    print("")
                print("Undocumented commands:")
                print("=" * 25)
                for each in self.undoced_commands:
                    print(each + "\t")
            return
        else:
            commands = [i for i in arg.split(" ") if i]
            unfound = []
            undoced = []
            for c in commands:
                if c not in self.commands:
                    unfound.append(c)
                    continue
                if c not in self.doced_commands:
                    undoced.append(c)
                    continue
                print("Help for command '{c}':".format(c=c))
                getattr(self, "help_" + c)()
                print("")

    def help_help(self):
        print("show help")

    def cmdloop(self):
        print(self.banner)
        while True:
            try:
                line = self.session.prompt(self.prompt)
                op = line.split(' ')[0]
                arg = line[len(op):].strip()
                try:
                    getattr(self, "do_" + op)(arg)
                except AttributeError as e:
                    self.error("Unknown command '{}'".format(op))
                except Exception as e:
                    self.error("Operation not supported.")
                    print(e)
            except KeyboardInterrupt:
                break
            except EOFError:
                break
        print("goodbye")

    def error(self, msg):
        print self.error_prompt, msg

    def info(self, msg):
        print self.info_prompt, msg
Beispiel #14
0
class CmdLoop:
    def __init__(self):
        self.name = 'main'
        self.completer = WordCompleter(
            ['listeners', 'sessions', 'modules', 'stagers', 'exit'],
            ignore_case=True)
        self.prompt_session = PromptSession(
            'ST ≫ ',
            bottom_toolbar=bottom_toolbar,
            completer=self.completer,
            auto_suggest=AutoSuggestFromHistory()
            #rprompt=get_rprompt,
            #style=rprompt_style
        )

        self.contexts = [
            Listeners(self.prompt_session),
            Sessions(self.prompt_session),
            Modules(self.prompt_session),
            Stagers(self.prompt_session)
        ]

        self.current_context = self

    def switched_context(self, result):
        for ctx in self.contexts:
            if result == ctx.name:
                self.prompt_session.message = ctx.prompt
                self.prompt_session.completer = ctx.completer
                self.current_context = ctx
                return True
        return False

    def parse_result(self, result):
        if len(result):
            if not self.switched_context(result):
                command = split(result)
                try:
                    logging.debug(
                        f"command: {command[0]} args: {command[1:]} ctx: {self.current_context.name}"
                    )

                    bound_cmd_handler = functools.partial(getattr(
                        self.current_context, command[0]),
                                                          args=command[1:])
                    run_in_terminal(bound_cmd_handler)
                except AttributeError:
                    print_bad(f"Unknown command '{command[0]}'")
                    if args['--debug']:
                        traceback.print_exc()
                except DocoptExit as e:
                    print(str(e))
                except SystemExit:
                    pass

    def run_resource_file(self):
        with open(args['--resource-file']) as resource_file:
            for cmd in resource_file:
                result = self.prompt_session.prompt(accept_default=True,
                                                    default=cmd.strip())
                self.parse_result(result)

    def __call__(self):
        if args['--resource-file']:
            self.run_resource_file()

        while True:
            result = self.prompt_session.prompt()
            if result == 'exit':
                break

            self.parse_result(result)
Beispiel #15
0
class Console(object):
    ''' Console user module '''

    def __init__(self, data_buffer_in,
                                       data_condition_in,
                                       output_lock):


        self.data_buffer_in = data_buffer_in
        self.data_condition_in = data_condition_in

        self._running = False
        self.name = 'Console'
        self.module_id = Module.CONSOLE
        self.output_lock = output_lock

        # First message to console , current jobs started
        self.send_message(MessageSubType.SHOW_JOBS,
                                          Module.CONTROL_MANAGER, [])


        self.console_history = FileHistory('history.dat')
        self.session = PromptSession(history=self.console_history,
                                                                 auto_suggest=AutoSuggestFromHistory(),
                                                                 enable_history_search=True)

        self.syspce_completer = WordCompleter(
                        [
                                "run",
                                "jobs",
                                "stop_job",
                                "show_config",
                                "show_alerts",
                                "stats",
                                "set",
                                "info",
                                "ps",
                                "exit",
                        ],
                        meta_dict={
                                "run": "Run actions based on syspce config",
                                "jobs": "Show current active Jobs",
                                "set": "[var] [value] Sets config parameters",
                                "stop_job": "[JobId] Stops a Job by job name",
                                "show_config": "Show current config",
                                "show_alerts": "Show alerts detected",
                                "stats": "List statistics for hostsnames",
                                "info": "[pid] [eventid] [computer] Show eventid details from a process",
                                "ps": "[tree_id] [computer] Processes list, treeid and computer is optional",
                                "exit": "Bye bye",
                        },
                        ignore_case=True,
                        )


    def run(self):
        ''' Thread console main code'''

        self._running = True
        log.debug("%s working..." % (self.name))

        while self._running:
            try:
                #command = unicode(raw_input("SYSPCE#>"), 'utf-8')

                command = self.session.prompt('SYSPCE#>',
                                                completer=self.syspce_completer,
                                                complete_style=CompleteStyle.MULTI_COLUMN)

            except ValueError, e:
                print "Input error: %s" % str(e)
                command = "exit"

            if (command == "jobs"):
                self.send_message(MessageSubType.SHOW_JOBS,
                                                  Module.CONTROL_MANAGER, [])

            elif(re.match("^run", command)):
                self.send_message(MessageSubType.RUN,
                                                  Module.CONTROL_MANAGER, [])
                self.s_print('Runnig actions in config...')

            elif(re.match("^stats", command)):
                self.send_message(MessageSubType.STATS,
                                                  Module.CONTROL_MANAGER, [])
                self.s_print('Runnig stats')

            elif(("show commands" in command) or ("help" in command)):
                self.help()

            elif(re.match("^show_config", command)):
                self.send_message(MessageSubType.SHOW_CONFIG,
                                                  Module.CONTROL_MANAGER, [])

            elif(re.match("^stop_job ", command)):
                try:
                    job_name = command.split('stop_job ')[1].replace(' ','')
                    self.send_message(MessageSubType.STOP_JOB,
                                                      Module.CONTROL_MANAGER, [job_name])
                except Exception, e:
                    self.s_print('Command error %s' % e)

            elif(re.match("^set", command)):
                c_splited = self.get_params(command)
                try:
                    var = c_splited[1]
                    value = c_splited[2]
                    self.send_message(MessageSubType.SET_CONFIG,
                                                      Module.CONTROL_MANAGER,
                                                      [var, value])

                except Exception, e:
                    self.s_print('Command error %s' % e)
Beispiel #16
0
                         ('CMLL', scrambler333.get_CMLL_scramble),
                         ('CLL', scrambler333.get_CLL_scramble),
                         ('ELL', scrambler333.get_ELL_scramble),
                         ('LSLL', scrambler333.get_LSLL_scramble),
                         ('RU', scrambler333.get_2genRU_scramble),
                         ('STOPWATCH', stopwatch), ('HELP', get_help),
                         ('QUIT', sys.exit)])

history_location = environ.get(
    "SCRAMBLE_HISTORY", path.join(path.expanduser("~"),
                                  ".scramble_history.txt"))

symbol_completer = WordCompleter(list(scrambles.keys()) + ["HELP"],
                                 ignore_case=True)
session: PromptSession[str] = PromptSession(
    history=FileHistory(history_location),
    completer=symbol_completer,
    auto_suggest=AutoSuggestFromHistory())  # type: ignore


def parse_user_input(string_from_user: str,
                     selected_scramble: Optional[str]) -> Tuple[str, int]:
    """Parses the scramble from the user

    >>> parse_user_input("3X3 5", None)
    ('3x3', 5)
    >>> parse_user_input("5", "3x3")
    ('3x3', 5)
    >>> parse_user_input("RU 3", "MEGAMINX")
    ('RU', 3)
    >>> parse_user_input("SQUARE ONE 10", "4x4")
    ('SQUARE ONE', 10)
Beispiel #17
0
def main():
    global login_status
    session = PromptSession()
    print('Eksi Suser Engelle')
    print('Browser is initializing...')
    
    engelle = eksi_engelle()
    
    while True:
        try:
            while login_status == False:
                print('You need to Login')
                USERNAME = input("email    : ")
                PASSWORD = getpass("password : ")
                
                if engelle.login(USERNAME,PASSWORD) == True:
                    print('Login successful')                
                    login_status = True
                else:
                    print('Login Failed')

            try:
                text = session.prompt('>',completer=commands)
                command = text.split()[0]
                value = text.split()[1]

            except IndexError:
                print('S + tab for Suser ')
                print('E + tab for EntryNo ')
                print('B + tab for Blocked Count ')
                continue

            # command Suser 
            if  command== 'Suser':
                engelle.bySuser(value)
                print( value, ' is blocking')
            #command EntryNo
            elif command == 'EntryNo':
                print( 'Fav list is blocking')
                engelle.byEntry(value)
            #command Blocked_List
            elif command == 'Blocked':
                print(engelle.blockedSuserList())

            #wrong command 
            else:
                print('wrong command')
                print('You entered:', text.split()[1])

        except KeyboardInterrupt:
            break
        except EOFError:
            break

    if login_status == True:
        engelle.logout()
        engelle.close() 
    
    engelle.quit()
    login_status = False
    print('GoodBye!')
Beispiel #18
0
def cli(client):
    kb = KeyBindings()

    @kb.add('c-space')
    def _(event):
        """
        Initialize autocompletion, or select the next completion.
        """
        buff = event.app.current_buffer
        if buff.complete_state:
            buff.complete_next()
        else:
            buff.start_completion(select_first=False)

    @kb.add('enter', filter=has_selected_completion)
    def _(event):
        """
        Makes the enter key work as the tab key only when showing the menu.
        """

        event.current_buffer.complete_state = None
        b = event.cli.current_buffer
        b.complete_state = None

    def _process_args(args, string=True):
        kwargs = {}
        execute = True
        skip_index = None
        for i, arg in enumerate(args):
            if i == skip_index:
                continue
            arg = arg.strip()
            if "=" in arg:
                a, val = arg.split("=")
                if not string:
                    if "," in val:
                        val = val.split(",")
                        val = [int(v) for v in val]
                    else:
                        val = int(val)
                kwargs[a] = val
            else:
                a, val = arg, args[i + 1]
                try:
                    if not string:
                        if "," in val:
                            val = val.split(",")
                            val = [int(v) for v in val]
                        else:
                            val = int(val)
                    kwargs[a] = val
                    skip_index = i + 1
                except TypeError:
                    click.secho("Error parsing arguments!", fg='yellow')
                    execute = False
                    break
                except ValueError:
                    click.secho("Error parsing argument", fg='yellow')
                    execute = False
                    break
        return kwargs, execute

    session = PromptSession(lexer=PygmentsLexer(PythonLexer),
                            completer=CmdCompleter(client),
                            style=style,
                            complete_while_typing=True,
                            bottom_toolbar=bottom_toolbar,
                            key_bindings=kb,
                            history=FileHistory('.pymodhis'),
                            auto_suggest=AutoSuggestFromHistory())
    click.secho("{}".format(TITLE), fg='green')
    result = None
    while True:
        try:

            text = session.prompt('> ', complete_while_typing=True)
            if text.strip().lower() == 'help':
                print_formatted_text(HTML("<u>Available commands:</u>"))
                for cmd, obj in sorted(session.completer.commands.items()):
                    if cmd != 'help':
                        print_formatted_text(
                            HTML("<skyblue>{:45s}</skyblue>"
                                 "<seagreen>{:100s}"
                                 "</seagreen>".format(cmd, obj.help_text)))

                continue
            elif text.strip().lower() == 'exit':
                raise EOFError()
            elif text.strip().lower().startswith("client."):
                try:
                    text = text.strip().split()
                    cmd = text[0].split(".")[1]
                    args = text[1:]
                    kwargs, execute = _process_args(args, string=False)
                    if execute:
                        if text[0] in CLIENT_ATTRIBUTES:
                            result = Result(getattr(client, cmd))
                        else:
                            result = Result(getattr(client, cmd)(**kwargs))
                        result.print_result()
                except Exception as e:
                    click.secho(repr(e), fg='red')
            elif text.strip().lower().startswith("result."):
                if result:
                    words = text.lower().split()
                    if words[0] == 'result.raw':
                        result.raw()
                    if words[0] == 'result.decode':
                        args = words[1:]
                        kwargs, execute = _process_args(args)
                        if execute:
                            result.decode(**kwargs)
        except KeyboardInterrupt:
            continue  # Control-C pressed. Try again.
        except EOFError:
            break  # Control-D pressed.
        except Exception as e:  # Handle all other exceptions
            click.secho(str(e), fg='red')

    click.secho('GoodBye!', fg='blue')
Beispiel #19
0
#!/usr/bin/env python
from prompt_toolkit import PromptSession
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.styles import Style

import click

words = ['youzark', 'hyx', 'white']
completer = WordCompleter(words)

styles = Style.from_dict({"bottom-toolbar": "#333333 bg:#ffcc00"})


def buttom_toolbar():
    toolbar_content = [("class:bottom-toolbar", "ctl-d or ctl-c to exit")]
    return toolbar_content


session = PromptSession(completer=completer,
                        bottom_toolbar=buttom_toolbar,
                        style=styles)


@click.command()
@click.option("--party", help='Party file to load')
def main_loop():
    settings = {'party_file': party}
    while True:
        user_input = session.prompt("")
        print(f"you have enterd '{user_input}'")
Beispiel #20
0
 def __init__(self):
     self.session = PromptSession()
     self.config_mode = False
     self.prompt = 'brewer@localhost> '
     self.config_prompt = 'brewer@localhost# '
Beispiel #21
0
class cruxformat:

    """
    This class is responsible for providing the cosmetic appearance of
    the command line interface, the behaviour itself is defined in cruxli.
    Much of the presentation options here are goverend by prompt_toolkit

    The command line interface has two basic modes, operational and
    configuration modes.
    """

    DEFAULT_OPER_COMMANDS = {
        'configure': 'enter configuration mode',
        'exit':      'exit from the CLI interface',
        'show':      'operational status'
    }

    def __init__(self):
        self.session = PromptSession()
        self.config_mode = False
        self.prompt = 'brewer@localhost> '
        self.config_prompt = 'brewer@localhost# '

    @staticmethod
    def bottom_toolbar():
        return HTML('Connected')

    def welcome(self):
        print('Welcome to BREWERS COMMAND LINE INTERFACE')
        return self.opermode_prompt()

    def configmode_prompt(self):
        print("")
        print("[edit] ")
        return self.session.prompt(self.config_prompt,
                                   bottom_toolbar=cruxformat.bottom_toolbar,
                                   completer=self.get_oper_mode_command_list(),
                                   complete_while_typing=True,
                                   validate_while_typing=True,
                                   auto_suggest=AutoSuggestFromHistory())

    def opermode_prompt(self):
        return self.session.prompt(self.prompt,
                                   bottom_toolbar=cruxformat.bottom_toolbar,
                                   completer=self.get_oper_mode_command_list(),
                                   complete_while_typing=True,
                                   validate_while_typing=True,
                                   auto_suggest=AutoSuggestFromHistory())

    def get_oper_mode_command_list(self):
        return WordCompleter(self.DEFAULT_OPER_COMMANDS.keys())

    def opermode_error(self, line):
        """
        When a user makes a mistake within operational mode provide some
        guidance to the user including a list of commands that are valid
        """
        print('%s\nError: expecting...\n' % (line))
        for command in self.DEFAULT_OPER_COMMANDS:
            print('%s%s - %s' % (command, ' '*(10-len(command)),
                                 self.DEFAULT_OPER_COMMANDS[command]))
        print("[error][%s]" % (self.get_time()))

    def get_time(self):
        return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
Beispiel #22
0
def implant_handler_command_loop(user, printhelp="", autohide=None):
    while (True):
        session = PromptSession(history=FileHistory('%s/.top-history' %
                                                    PoshProjectDirectory),
                                auto_suggest=AutoSuggestFromHistory())

        try:
            if user is not None:
                print("User: "******"%s%s" % (user, Colours.GREEN))
                print()

            C2 = get_c2server_all()
            killdate = datetime.strptime(C2.KillDate, '%Y-%m-%d').date()
            datedifference = number_of_days(date.today(), killdate)
            if datedifference < 8:
                print(Colours.RED +
                      ("\nKill Date is - %s - expires in %s days" %
                       (C2.KillDate, datedifference)))
                print(Colours.END)
                print()

            implants = get_implants()
            if implants:
                for implant in implants:
                    ID = implant.ImplantID
                    LastSeen = implant.LastSeen
                    Hostname = implant.Hostname
                    Domain = implant.Domain
                    URLID = implant.URLID
                    DomainUser = implant.User
                    Arch = implant.Arch
                    PID = implant.PID
                    Pivot = implant.Pivot
                    Sleep = implant.Sleep.strip()
                    Label = implant.Label

                    apmsuspendshut = False

                    pwrStatus = get_powerstatusbyrandomuri(implant.RandomURI)
                    if pwrStatus is not None:
                        if Label is not None:
                            Label += " "
                        else:
                            Label = ""
                        apmstatus = pwrStatus[2].lower()

                        if (apmstatus == "shutdown"):
                            Label += "SHTDWN "
                            apmsuspendshut = True
                        elif (apmstatus == "suspend"
                              or apmstatus == "querysuspend"):
                            Label += "SUSPND "
                            apmsuspendshut = True

                        if not apmsuspendshut:
                            if (pwrStatus[7]):
                                Label += "LOCKED "
                            if (not pwrStatus[8]):
                                Label += "SCRN OFF "

                            if (not pwrStatus[3]):
                                if (pwrStatus[6] is not None
                                        and pwrStatus[6].isdigit()):
                                    Label += ("DSCHRG: %s%% " % pwrStatus[6])
                                else:
                                    Label += ("DSCHRG ")

                    Pivot = get_implant_type_prompt_prefix(ID)
                    LastSeenTime = datetime.strptime(LastSeen,
                                                     "%Y-%m-%d %H:%M:%S")
                    LastSeenTimeString = datetime.strftime(
                        LastSeenTime, "%Y-%m-%d %H:%M:%S")
                    now = datetime.now()
                    if (Sleep.endswith('s')):
                        sleep_int = int(Sleep[:-1])
                    elif (Sleep.endswith('m')):
                        sleep_int = int(Sleep[:-1]) * 60
                    elif (Sleep.endswith('h')):
                        sleep_int = int(Sleep[:-1]) * 60 * 60
                    else:
                        print(Colours.RED)
                        print("Incorrect sleep format: %s" % Sleep)
                        print(Colours.GREEN)
                        continue
                    nowMinus3Beacons = now - timedelta(seconds=(sleep_int * 3))
                    nowMinus10Beacons = now - timedelta(seconds=(sleep_int *
                                                                 10))
                    nowMinus30Beacons = now - timedelta(seconds=(sleep_int *
                                                                 30))
                    sID = "[" + str(ID) + "]"
                    if not Label:
                        sLabel = ""
                    else:
                        Label = Label.strip()
                        sLabel = Colours.BLUE + "[" + Label + "]" + Colours.GREEN

                    if "C#;PB" in Pivot:
                        print(
                            Colours.BLUE +
                            "%s: Seen:%s | PID:%s | %s | PBind | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, Domain, DomainUser, Hostname, Arch,
                               Pivot, sLabel))
                    elif nowMinus30Beacons > LastSeenTime and autohide:
                        pass
                    elif nowMinus10Beacons > LastSeenTime:
                        print(
                            Colours.RED +
                            "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, URLID, Domain, DomainUser, Hostname,
                               Arch, Pivot, sLabel))
                    elif nowMinus3Beacons > LastSeenTime:
                        print(
                            Colours.YELLOW +
                            "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, URLID, Domain, DomainUser, Hostname,
                               Arch, Pivot, sLabel))
                    else:
                        print(
                            Colours.GREEN +
                            "%s: Seen:%s | PID:%s | %s | URLID: %s | %s\\%s @ %s (%s) %s %s"
                            % (sID.ljust(4), LastSeenTimeString, PID.ljust(5),
                               Sleep, URLID, Domain, DomainUser, Hostname,
                               Arch, Pivot, sLabel))
            else:
                now = datetime.now()
                print(Colours.RED + "No Implants as of: %s" %
                      now.strftime("%Y-%m-%d %H:%M:%S"))

            if printhelp:
                print(printhelp)

            command = session.prompt(
                "\nSelect ImplantID or ALL or Comma Separated List (Enter to refresh):: ",
                completer=FirstWordFuzzyWordCompleter(SERVER_COMMANDS,
                                                      WORD=True))
            print("")

            command = command.strip()
            if (command == "") or (command == "back") or (command == "clear"):
                do_back(user, command)
                continue
            if command.startswith("generate-reports"):
                do_generate_reports(user, command)
                continue
            if command.startswith("generate-csvs"):
                do_generate_csvs(user, command)
                continue
            if command.startswith("message "):
                do_message(user, command)
                continue
            if command.startswith("show-hosted-files"):
                do_show_hosted_files(user, command)
                continue
            if command.startswith("add-hosted-file"):
                do_add_hosted_file(user, command)
                continue
            if command.startswith("disable-hosted-file"):
                do_disable_hosted_file(user, command)
                continue
            if command.startswith("enable-hosted-file"):
                do_enable_hosted_file(user, command)
                continue
            if command.startswith("show-urls") or command.startswith(
                    "list-urls"):
                do_show_urls(user, command)
                continue
            if command.startswith("add-autorun"):
                do_add_autorun(user, command)
                continue
            if command.startswith("list-autorun"):
                do_list_autoruns(user, command)
                continue
            if command.startswith("del-autorun"):
                do_del_autorun(user, command)
                continue
            if command.startswith("nuke-autorun"):
                do_nuke_autoruns(user, command)
                continue
            if command.startswith("kill"):
                do_del_task(user, command)
                continue
            if (command == "automigrate-frompowershell") or (command == "am"):
                do_automigrate_frompowershell(user, command)
                continue
            if command.startswith("show-serverinfo"):
                do_show_serverinfo(user, command)
                continue
            if command.startswith("turnoff-notifications"):
                do_turnoff_notifications(user, command)
                continue
            if command.startswith("turnon-notifications"):
                do_turnon_notifications(user, command)
                continue
            if command.startswith("set-pushover-applicationtoken"):
                do_set_pushover_applicationtoken(user, command)
                continue
            if command.startswith("set-pushover-userkeys"):
                do_set_pushover_userkeys(user, command)
                continue
            if command.startswith("get-killdate"):
                do_get_killdate(user, command)
                continue
            if command.startswith("set-killdate"):
                do_set_killdate(user, command)
                continue
            if command.startswith("set-defaultbeacon"):
                do_set_defaultbeacon(user, command)
                continue
            if command == "get-opsec-events":
                do_get_opsec_events(user, command)
                continue
            if command == "add-opsec-event":
                do_insert_opsec_events(user, command)
                continue
            if command == "del-opsec-event":
                do_del_opsec_events(user, command)
                continue
            if command.startswith("opsec"):
                do_opsec(user, command)
                continue
            if command.startswith("listmodules"):
                do_listmodules(user, command)
                continue
            if command.startswith('creds ') or command.strip() == "creds":
                do_creds(user, command)
                input("Press Enter to continue...")
                clear()
                continue
            if (command == "pwnself") or (command == "p"):
                do_pwnself(user, command)
                continue
            if command == "tasks":
                do_tasks(user, command)
                continue
            if command == "cleartasks":
                do_cleartasks(user, command)
                continue
            if command.startswith("quit"):
                do_quit(user, command)
                continue
            if command.startswith("createdaisypayload"):
                do_createdaisypayload(user, command)
                continue
            if command.startswith("createproxypayload"):
                do_createnewpayload(user, command)
                continue
            if command.startswith("createnewpayload"):
                do_createnewpayload(user, command)
                continue
            if command.startswith("createnewshellcode"):
                do_createnewpayload(user, command, shellcodeOnly=True)
                continue
            if command == "help":
                do_help(user, command)
                continue
            if command == "history":
                do_history(user, command)
                continue
            if command.startswith("use "):
                do_use(user, command)
            implant_command_loop(command, user)
        except KeyboardInterrupt:
            clear()
            continue
        except EOFError:
            new_c2_message("%s logged off." % user)
            sys.exit(0)
        except Exception as e:
            if 'unable to open database file' not in str(e):
                print_bad("Error: %s" % e)
                traceback.print_exc()
Beispiel #23
0
    class REPLApplication(ConsoleApplication):
        def __init__(self):
            self._script = None
            self._seqno = 0
            self._ready = threading.Event()
            self._stopping = threading.Event()
            self._errors = 0
            config_dir = self._get_or_create_config_dir()
            self._history = FileHistory(os.path.join(config_dir, 'history'))
            self._completer = FridaCompleter(self)
            self._cli = None
            self._last_change_id = 0
            self._script_monitor = None
            self._monitored_file = None

            super(REPLApplication, self).__init__(self._process_input, self._on_stop)

            self._dumb_stdin_reader = None if self._have_terminal and not self._plain_terminal else DumbStdinReader(valid_until=self._stopping.is_set)

            if not self._have_terminal:
                self._rpc_complete_server = start_completion_thread(self)

        def _add_options(self, parser):
            parser.add_option("-l", "--load", help="load SCRIPT", metavar="SCRIPT",
                              type='string', action='store', dest="user_script", default=None)
            parser.add_option("-c", "--codeshare", help="load CODESHARE_URI", metavar="CODESHARE_URI",
                              type='string', action='store', dest="codeshare_uri", default=None)
            parser.add_option("-e", "--eval", help="evaluate CODE", metavar="CODE",
                              type='string', action='append', dest="eval_items", default=None)
            parser.add_option("-q", help="quiet mode (no prompt) and quit after -l and -e",
                              action='store_true', dest="quiet", default=False)
            parser.add_option("--no-pause", help="automatically start main thread after startup",
                              action='store_true', dest="no_pause", default=False)
            parser.add_option("-o", "--output", help="output to log file", dest="logfile", default=None)

        def _initialize(self, parser, options, args):
            if options.user_script is not None:
                self._user_script = os.path.abspath(options.user_script)
                with codecs.open(self._user_script, 'rb', 'utf-8') as f:
                    pass
            else:
                self._user_script = None
            self._codeshare_uri = options.codeshare_uri
            self._codeshare_script = None
            self._pending_eval = options.eval_items
            self._quiet = options.quiet
            self._no_pause = options.no_pause
            if options.logfile is not None:
                self._logfile = open(options.logfile, 'w')
            else:
                self._logfile = None

        def _log(self, level, text):
            ConsoleApplication._log(self, level, text)
            if self._logfile is not None:
                self._logfile.write(text + "\n")

        def _usage(self):
            return "usage: %prog [options] target"

        def _needs_target(self):
            return True

        def _start(self):
            self._prompt_string = self._create_prompt()

            if self._codeshare_uri is not None:
                self._codeshare_script = self._load_codeshare_script(self._codeshare_uri)
                if self._codeshare_script is None:
                    self._print("Exiting!")
                    self._exit(1)
                    return

            try:
                self._load_script()
            except Exception as e:
                self._update_status("Failed to load script: {error}".format(error=e))
                self._exit(1)
                return

            if self._spawned_argv is not None:
                if self._no_pause:
                    self._update_status(
                        "Spawned `{command}`. Resuming main thread!".format(command=" ".join(self._spawned_argv)))
                    self._do_magic("resume")
                else:
                    self._update_status(
                        "Spawned `{command}`. Use %resume to let the main thread start executing!".format(
                            command=" ".join(self._spawned_argv)))
            else:
                self._clear_status()
            self._ready.set()

        def _on_stop(self):
            def set_return():
                raise EOFError()

            self._stopping.set()

            if self._cli is not None:
                try:
                    self._cli.eventloop.call_from_executor(set_return)
                except Exception:
                    pass

        def _stop(self):
            self._unload_script()
            self._unmonitor_script()

            if self._logfile is not None:
                self._logfile.close()

            if not self._quiet:
                self._print("\nThank you for using Frida!")

        def _load_script(self):
            self._monitor_script()
            self._seqno += 1
            script = self._session.create_script(name="repl%d" % self._seqno, source=self._create_repl_script())
            script.set_log_handler(self._log)
            self._unload_script()
            self._script = script

            def on_message(message, data):
                self._reactor.schedule(lambda: self._process_message(message, data))

            script.on('message', on_message)
            script.load()

        def _unload_script(self):
            if self._script is None:
                return

            try:
                self._script.unload()
            except:
                pass
            self._script = None

        def _monitor_script(self):
            if self._monitored_file == self._user_script:
                return

            self._unmonitor_script()

            if self._user_script is not None:
                monitor = frida.FileMonitor(self._user_script)
                monitor.on('change', self._on_change)
                monitor.enable()
                self._script_monitor = monitor
            self._monitored_file = self._user_script

        def _unmonitor_script(self):
            if self._script_monitor is None:
                return

            self._script_monitor.disable()
            self._script_monitor = None

        def _process_input(self, reactor):
            if not self._quiet:
                self._print_startup_message()

            while self._ready.wait(0.5) != True:
                if not reactor.is_running():
                    return

            while True:
                expression = ""
                line = ""
                while len(expression) == 0 or line.endswith("\\"):
                    if not reactor.is_running():
                        return

                    prompt = "[%s]" % self._prompt_string + "-> " if len(expression) == 0 else "... "

                    pending_eval = self._pending_eval
                    if pending_eval is not None:
                        if len(pending_eval) > 0:
                            expression = pending_eval.pop(0)
                            if not self._quiet:
                                self._print(prompt + expression)
                        else:
                            self._pending_eval = None
                    else:
                        if self._quiet:
                            self._exit_status = 0 if self._errors == 0 else 1
                            return

                        try:
                            if self._have_terminal and not self._plain_terminal:
                                self._cli = PromptSession(lexer=PygmentsLexer(JavascriptLexer),
                                                          history=self._history, completer=self._completer)

                                line = self._cli.prompt(prompt)
                            else:
                                line = self._dumb_stdin_reader.read_line(prompt)
                                self._print(line)
                        except EOFError:
                            if not self._have_terminal and os.environ.get("TERM", '') != "dumb":
                                while not self._stopping.wait(1):
                                    pass
                            return
                        except KeyboardInterrupt:
                            line = ""
                            if not self._have_terminal:
                                sys.stdout.write("\n" + prompt)
                            continue
                        if len(line.strip()) > 0:
                            if len(expression) > 0:
                                expression += "\n"
                            expression += line.rstrip("\\")

                if expression.endswith("?"):
                    try:
                        self._print_help(expression)
                    except JavaScriptError as e:
                        error = e.error
                        self._print(Fore.RED + Style.BRIGHT + error['name'] + Style.RESET_ALL + ": " + error['message'])
                    except frida.InvalidOperationError:
                        return
                elif expression.startswith("%"):
                    self._do_magic(expression[1:].rstrip())
                elif expression in ("exit", "quit", "q"):
                    return
                elif expression == "help":
                    self._print("Help: #TODO :)")
                else:
                    if not self._eval_and_print(expression):
                        self._errors += 1

        def _eval_and_print(self, expression):
            success = False
            try:
                (t, value) = self._evaluate(expression)
                if t in ('function', 'undefined', 'null'):
                    output = t
                elif t == 'binary':
                    output = hexdump(value).rstrip("\n")
                else:
                    output = json.dumps(value, sort_keys=True, indent=4, separators=(",", ": "))
                success = True
            except JavaScriptError as e:
                error = e.error
                output = Fore.RED + Style.BRIGHT + error['name'] + Style.RESET_ALL + ": " + error['message']
            except frida.InvalidOperationError:
                return success
            self._print(output)
            return success

        def _print_startup_message(self):
            self._print("""\
     ____
    / _  |   Frida {version} - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://www.frida.re/docs/home/""".format(version=frida.__version__))

        def _print_help(self, expression):
            # TODO: Figure out docstrings and implement here. This is real jankaty right now.
            help_text = ""
            if expression.endswith(".?"):
                expression = expression[:-2] + "?"

            obj_to_identify = [x for x in expression.split(' ') if x.endswith("?")][0][:-1]
            (obj_type, obj_value) = self._evaluate(obj_to_identify)

            if obj_type == "function":
                signature = self._evaluate("%s.toString()" % obj_to_identify)[1]
                clean_signature = signature.split("{")[0][:-1].split('function ')[-1]

                if "[native code]" in signature:
                    help_text += "Type:      Function (native)\n"
                else:
                    help_text += "Type:      Function\n"

                help_text += "Signature: %s\n" % clean_signature
                help_text += "Docstring: #TODO :)"

            elif obj_type == "object":
                help_text += "Type:      Object\n"
                help_text += "Docstring: #TODO :)"

            elif obj_type == "boolean":
                help_text += "Type:      Boolean\n"
                help_text += "Docstring: #TODO :)"

            elif obj_type == "string":
                help_text += "Type:      Boolean\n"
                help_text += "Text:      %s\n" % self._evaluate("%s.toString()" % obj_to_identify)[1]
                help_text += "Docstring: #TODO :)"

            self._print(help_text)

        # Negative means at least abs(val) - 1
        _magic_command_args = {
            'resume': 0,
            'load': 1,
            'reload': 0,
            'unload': 0,
            'time': -2  # At least 1 arg
        }

        def _do_magic(self, statement):
            tokens = statement.split(" ")
            command = tokens[0]
            args = tokens[1:]

            required_args = self._magic_command_args.get(command)

            if required_args == None:
                self._print("Unknown command: {}".format(command))
                self._print("Valid commands: {}".format(", ".join(self._magic_command_args.keys())))
                return

            atleast_args = False
            if required_args < 0:
                atleast_args = True
                required_args = abs(required_args) - 1

            if (not atleast_args and len(args) != required_args) or \
                    (atleast_args and len(args) < required_args):
                self._print("{cmd} command expects {atleast}{n} argument{s}".format(
                    cmd=command, atleast='atleast ' if atleast_args else '', n=required_args,
                    s='' if required_args == 1 else ' '))
                return

            if command == 'resume':
                self._reactor.schedule(lambda: self._resume())
            elif command == 'load':
                old_user_script = self._user_script
                self._user_script = os.path.abspath(args[0])
                if not self._reload():
                    self._user_script = old_user_script
            elif command == 'reload':
                self._reload()
            elif command == 'unload':
                self._user_script = None
                self._reload()
            elif command == 'time':
                self._eval_and_print('''
                    (function () {
                        var _startTime = Date.now();
                        var _result = eval({expression});
                        var _endTime = Date.now();
                        console.log('Time: ' + (_endTime - _startTime).toLocaleString() + ' ms.');
                        return _result;
                    })();'''.format(expression=json.dumps(' '.join(args))))

        def _reload(self):
            completed = threading.Event()
            result = [None]

            def do_reload():
                try:
                    self._load_script()
                except Exception as e:
                    result[0] = e
                completed.set()

            self._reactor.schedule(do_reload)
            completed.wait()
            if result[0] is None:
                return True
            else:
                self._print("Failed to load script: {error}".format(error=result[0]))
                return False

        def _create_prompt(self):
            device_type = self._device.type
            type_name = self._target[0]
            if type_name == 'pid':
                if self._target[1] == 0:
                    target = 'SystemSession'
                else:
                    target = 'PID::%u' % self._target[1]
            elif type_name == 'file':
                target = os.path.basename(self._target[1][0])
            else:
                target = self._target[1]

            if device_type in ('local', 'remote'):
                prompt_string = "%s::%s" % (device_type.title(), target)
            else:
                prompt_string = "%s::%s" % (self._device.name, target)

            return prompt_string

        def _evaluate(self, text):
            result = self._script.exports.evaluate(text)
            if is_byte_array(result):
                return ('binary', result)
            elif isinstance(result, dict):
                return ('binary', bytes())
            elif result[0] == 'error':
                raise JavaScriptError(result[1])
            else:
                return result

        def _process_message(self, message, data):
            message_type = message['type']
            if message_type == 'error':
                text = message.get('stack', message['description'])
                self._log('error', text)
                self._errors += 1
            else:
                self._print("message:", message, "data:", data)

        def _on_change(self, changed_file, other_file, event_type):
            if event_type == 'changes-done-hint':
                return
            self._last_change_id += 1
            change_id = self._last_change_id
            self._reactor.schedule(lambda: self._process_change(change_id), delay=0.05)

        def _process_change(self, change_id):
            if change_id != self._last_change_id:
                return
            try:
                self._load_script()
            except Exception as e:
                self._print("Failed to load script: {error}".format(error=e))

        def _create_repl_script(self):
            user_script = ""

            if self._codeshare_script is not None:
                user_script = self._codeshare_script

            if self._user_script is not None:
                with codecs.open(self._user_script, 'rb', 'utf-8') as f:
                    user_script += f.read().rstrip("\r\n") + "\n\n// Frida REPL script:\n"

            return user_script + """\

rpc.exports.evaluate = function (expression) {
    try {
        var result = (1, eval)(expression);
        if (result instanceof ArrayBuffer) {
            return result;
        } else {
            var type = (result === null) ? 'null' : typeof result;
            return [type, result];
        }
    } catch (e) {
        return ['error', {
            name: e.name,
            message: e.message,
            stack: e.stack
        }];
    }
};
"""

        def _load_codeshare_script(self, uri):
            trust_store = self._get_or_create_truststore()

            project_url = "https://codeshare.frida.re/api/project/{}/".format(uri)
            response_json = None
            try:
                request = build_opener()
                request.addheaders = [('User-Agent', 'Frida v{} | {}'.format(frida.__version__, platform.platform()))]
                response = request.open(project_url)
                response_content = response.read().decode('utf-8')
                response_json = json.loads(response_content)
            except Exception as e:
                self._print("Got an unhandled exception while trying to retrieve {} - {}".format(uri, e))
                return None

            trusted_signature = trust_store.get(uri, "")
            fingerprint = hashlib.sha256(response_json['source'].encode('utf-8')).hexdigest()
            if fingerprint == trusted_signature:
                return response_json['source']

            self._print("""Hello! This is the first time you're running this particular snippet, or the snippet's source code has changed.

Project Name: {project_name}
Author: {author}
Slug: {slug}
Fingerprint: {fingerprint}
URL: {url}
            """.format(
                project_name=response_json['project_name'],
                author="@" + uri.split('/')[0],
                slug=uri,
                fingerprint=fingerprint,
                url="https://codeshare.frida.re/@{}".format(uri)
            ))

            while True:
                prompt_string = "Are you sure you'd like to trust this project? [y/N] "
                response = get_input(prompt_string)

                if response.lower() in ('n', 'no') or response == '':
                    return None

                if response.lower() in ('y', 'yes'):
                    self._print(
                        "Adding fingerprint {} to the trust store! You won't be prompted again unless the code changes.".format(
                            fingerprint))
                    script = response_json['source']
                    self._update_truststore({
                        uri: fingerprint
                    })
                    return script

        def _get_or_create_config_dir(self):
            config_dir = os.path.join(os.path.expanduser('~'), '.frida')
            if not os.path.exists(config_dir):
                os.makedirs(config_dir)
            return config_dir

        def _update_truststore(self, record):
            trust_store = self._get_or_create_truststore()
            trust_store.update(record)

            config_dir = self._get_or_create_config_dir()
            codeshare_trust_store = os.path.join(config_dir, "codeshare-truststore.json")

            with open(codeshare_trust_store, 'w') as f:
                f.write(json.dumps(trust_store))

        def _get_or_create_truststore(self):
            config_dir = self._get_or_create_config_dir()

            codeshare_trust_store = os.path.join(config_dir, "codeshare-truststore.json")

            if os.path.exists(codeshare_trust_store):
                try:
                    with open(codeshare_trust_store) as f:
                        trust_store = json.load(f)
                except Exception as e:
                    self._print(
                        "Unable to load the codeshare truststore ({}), defaulting to an empty truststore. You will be prompted every time you want to run a script!".format(
                            e))
                    trust_store = {}
            else:
                with open(codeshare_trust_store, 'w') as f:
                    f.write(json.dumps({}))
                trust_store = {}

            return trust_store
Beispiel #24
0
    def run_cli(self):
        # get catalog data before start
        self.refresher.refresh(self.executor, self.completer, [])
        # Load history into completer so it can learn user preferences
        history = FileHistory(os.path.expanduser('~/.voltsql_history'))
        self.completer.init_prioritization_from_history(history)

        session = PromptSession(lexer=PygmentsLexer(SqlLexer),
                                completer=self.completer,
                                style=style,
                                auto_suggest=AutoSuggestFromHistory(),
                                bottom_toolbar=self.bottom_toolbar,
                                key_bindings=self.create_key_bindings(),
                                multiline=True,
                                history=history)

        # directly assign multiline=False in PromptSession constructor will cause some unexpected behavior
        # due to some issue i don't know. This is a workaround.
        if not self.multiline:
            session.default_buffer.multiline = ~session.default_buffer.multiline

        option_str = "--servers={server} --port={port_number}{user}{password}{credentials}" \
                     "{ssl}{output_format}{output_skip_metadata}{stop_on_error}{kerberos} " \
                     "--query-timeout={number_of_milliseconds}".format(
            server=self.servers, port_number=self.port,
            user="******" + self.user if self.user else "",
            password="******" + self.password if self.password else "",
            credentials=" --credentials=" + self.credentials if self.credentials else "",
            kerberos=" --kerberos=" + self.kerberos if self.kerberos else "",
            number_of_milliseconds=self.query_timeout,
            ssl=" --ssl=" + self.ssl_set if self.ssl_set else " --ssl" if self.ssl else "",
            output_format=" --output-format=" + self.output_format if self.output_format else "",
            output_skip_metadata=" --output-skip-metadata" if self.output_skip_metadata else "",
            stop_on_error=" --stop-on-error=false" if not self.stop_on_error else ""
        )
        while True:
            try:
                sql_cmd = session.prompt('> ')
            except KeyboardInterrupt:
                break
            except EOFError:
                break
            else:
                stripped_cmd = sql_cmd.strip().lower().rstrip(';')
                if stripped_cmd == "refresh":
                    # use "refresh" command to force a fresh
                    self.refresher.refresh(self.executor, self.completer, [])
                    continue
                if stripped_cmd in ("quit", "exit"):
                    # exit
                    break
                if stripped_cmd == "help":
                    print(README)
                    continue
                if not stripped_cmd:
                    # do nothing when empty line
                    continue
                call("echo \"{sql_cmd}\" | sqlcmd {options}".format(
                    sql_cmd=sql_cmd, options=option_str),
                     shell=True)
                if self.auto_refresh:
                    self.refresher.refresh(self.executor, self.completer, [])
        print('GoodBye!')
Beispiel #25
0
class SpannerCli(object):
    client = None
    instance = None
    database = None
    project = None
    history = None

    def __init__(self, project=None, instance=None, database=None, credentials=None, with_pager=False,
                 inp=None, output=None):
        # setup environment variables
        # less option for pager
        if not os.environ.get(config.EnvironmentVariables.LESS):
            os.environ[config.EnvironmentVariables.LESS] = config.Constants.LESS_FLAG
        self.with_pager = with_pager
        self.logger = logging.getLogger('spanner-cli')
        self.logger.debug("Staring spanner-cli project=%s, instance=%s, database=%s", project, instance, database)
        self.project = project
        with warnings.catch_warnings(record=True) as warns:
            warnings.simplefilter("always")
            self.client = spanner.Client(
                project=self.project,
                credentials=credentials,
                client_info=client_info.ClientInfo(user_agent=__name__),
            )
            if len(warns) > 0:
                for w in warns:
                    self.logger.debug(w)
                    click.echo(message=w.message, err=True, nl=True)

        self.instance = self.client.instance(instance)
        self.database = self.instance.database(database)
        self.prompt_message = self.get_prompt_message()
        self.completer = SQLCompleter()
        self.open_history_file()
        self.rehash()
        self.session = PromptSession(
            message=self.prompt_message,
            lexer=PygmentsLexer(lexer.SpannerLexer),
            completer=DynamicCompleter(lambda: self.completer),
            style=style_from_pygments_cls(get_style_by_name(config.get_pygment_style())),
            history=self.history,
            auto_suggest=AutoSuggestFromHistory(),
            input_processors=[ConditionalProcessor(
                processor=HighlightMatchingBracketProcessor(
                    chars='[](){}'),
                filter=HasFocus(DEFAULT_BUFFER) & ~IsDone()  # pylint: disable=invalid-unary-operand-type
            )],
            input=inp,
            output=output,
        )

        self.formatter = tabular_output.TabularOutputFormatter('ascii')

    def rehash(self):
        """
        rehashing for completion
        """
        self.set_completion_databases()
        self.set_completion_tables()
        self.set_completion_columns()

    def set_completion_databases(self):
        data = self.list_databases()
        self.completer.set_databases(data)

    def set_completion_tables(self):
        sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG='' AND TABLE_SCHEMA='';"
        res = self.read_query(sql)
        tables = []
        for d in res.data:
            tables.append(d[0])
        self.completer.set_tables(tables)

    def set_completion_columns(self):
        sql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG='' AND TABLE_SCHEMA='' "
        res = self.read_query(sql)
        columns = []
        for d in res.data:
            columns.append(d[0])
        self.completer.set_columns(columns)

    def open_history_file(self):
        history_file = os.path.expanduser(os.environ.get(config.EnvironmentVariables.HISTORY_FILE,
                                                         config.Constants.HISTORY_FILE))
        if os.path.exists(os.path.dirname(history_file)):
            self.history = FileHistory(history_file)
        else:
            self.history = None

    def get_prompt_message(self) -> str:
        return f"Spanner [{self.project}/{self.instance.display_name}/{self.database.database_id}]:\n> "

    def list_databases(self):
        data = []
        try:
            databases = self.instance.list_databases()
            for d in databases:
                data.append(d.database_id)
        except api_exceptions.GoogleAPIError as e:
            # google.api_core.exceptions.PermissionDenied, if does not have sufficient permission
            self.logger.exception(e)
        return data

    def change_database(self, dbname):
        self.database = self.instance.database(dbname)
        self.prompt_message = self.get_prompt_message()

    def query(self, sql) -> structures.ResultContainer:
        self.logger.debug("QUERY: %s", sql)
        if queryutils.is_write_query(sql):
            return self.write_query(sql)
        if queryutils.is_ddl_query(sql):
            return self.ddl_query(sql)
        return self.read_query(sql)

    def read_query(self, sql) -> structures.ResultContainer:
        meta = {}
        if sql.strip().endswith('\\G'):
            meta['format'] = 'vertical'
            sql = sql[:-2]

        with self.database.snapshot() as snapshot:
            result_set = snapshot.execute_sql(sql,
                                              query_mode=types.spanner.ExecuteSqlRequest.QueryMode.PROFILE)
            data = []
            limit = config.Constants.MAX_RESULT
            count = 0
            for row in result_set:
                data.append(row)
                count = count+1
                if count > limit:
                    break
            header = []
            for h in result_set.fields:
                header.append(h.name)
            message = ""
            if result_set.stats:
                # stats.query_stats
                # {
                #   'elapsed_time': string_value: "0.91 msecs",
                #   'query_text': string_value: "select 1;"
                #   'rows_scanned': string_value: "0",
                #   'rows_returned': string_value: "1",
                #   'cpu_time': string_value: "0.23 msecs",
                #   'runtime_creation_time': string_value: "0 msecs",
                #   'query_plan_creation_time': string_value: "0.23 msecs"
                # }
                message = "rows_returned: {returned:,}, " \
                    "scanned: {scanned:}, " \
                    "elapsed_time: {elapsed}, " \
                    "cpu_time:{cpu}".format(
                        returned=int(result_set.stats.query_stats['rows_returned']),
                        scanned=int(result_set.stats.query_stats['rows_scanned']),
                        elapsed=result_set.stats.query_stats['elapsed_time'],
                        cpu=result_set.stats.query_stats['cpu_time'],
                    )
            if count > limit and message == "":
                message = f"returns over limit: {limit}, aborted to read all results, stats is not available."
            meta['message'] = message

        return structures.ResultContainer(
            data=data,
            header=header,
            **meta
        )

    def write_query(self, sql: str) -> structures.ResultContainer:
        meta = {}

        def execute(transaction):
            status, sequence = transaction.batch_update([sql])
            if status.code != 0:
                raise ValueError(f"code={status.code}, {status.message}")
            meta['message'] = f"{sequence[0]} row affected."

        self.database.run_in_transaction(execute)
        return structures.ResultContainer(
            data=[],
            header=[],
            **meta
        )

    def ddl_query(self, sql: str) -> structures.ResultContainer:
        sql = queryutils.clean(sql)
        if sql.upper().startswith("CREATE DATABASE") or sql.upper().startswith("DROP DATABASE"):
            return self.create_or_drop_database(sql)
        meta = {}
        operation = self.database.update_ddl([sql])
        operation.result()
        meta['message'] = "operation done."
        self.rehash()
        return structures.ResultContainer(
            data=[],
            header=[],
            **meta
        )

    def create_or_drop_database(self, sql: str) -> structures.ResultContainer:
        meta = {}
        database_id = queryutils.find_last_word(sql)
        database = self.instance.database(database_id, [])
        if sql.startswith("CREATE"):
            operation = database.create()
            operation.result()
            meta['message'] = f"Created database {database_id} on instance {self.instance.display_name}"
        elif sql.startswith("DROP"):
            database.drop()
            meta['message'] = f"Drop database {database_id} on instance {self.instance.display_name}"
        else:
            raise NotImplementedError(f"NotImplemented operation: {sql}")

        self.rehash()
        return structures.ResultContainer(
            data=[],
            header=[],
            **meta
        )

    def interact(self):  # pylint: disable=too-many-return-statements
        try:
            text = self.session.prompt(self.prompt_message)
        except KeyboardInterrupt:
            return
        except EOFError as e:
            raise e
        else:
            if not text.strip():
                return

        try:
            # command
            result = commands.execute(self, text)
            if result is not None:
                self.output(result)
            return
        except api_exceptions.GoogleAPIError as e:
            self.logger.exception(e)
            print("\n", e, "\n")
            return
        except EOFError as e:
            self.logger.exception(e)
            raise e
        except commands.CommandError as e:
            self.logger.exception(e)
            print("\n", e, "\n")
            return
        except commands.CommandNotFound:
            pass

        try:
            # query
            result = self.query(text)
            self.output(result)
            return
        except api_exceptions.GoogleAPICallError as e:
            message = "\n" + bytes(e.message, "utf8").decode("unicode_escape") + "\n"
            click.secho(message=message, err=True, nl=True, fg="red")
            self.logger.exception(e)
            return
        except Exception as e:  # pylint: disable=broad-except
            click.secho(message="\n" + str(e) + "\n", err=True, nl=True, fg="red")
            self.logger.exception(e)

    def output(self, result: structures.ResultContainer):
        if len(result) > 0:
            opt = {
                'dialect': 'unix',
                'disable_numparse': True,
                'preserve_whitespace': True,
                'column_types': str,
            }
            format_name = result.format()
            if format_name is not None:
                opt['format_name'] = format_name

            formatted = self.formatter.format_output(
                result.data, result.header, **opt)
            if self.with_pager:
                click.echo_via_pager("\n".join(list(formatted)))
            else:
                for n in formatted:
                    click.secho(n)
        result.print_message()

    def run(self):
        try:
            while True:
                self.interact()
        except EOFError:
            print("bye")

    def batch(self, query):
        if query is None:
            buf = []
            for l in sys.stdin:
                buf.append(l)
            query = ''.join(buf)
        try:
            # query
            result = self.query(query.strip())
            result.meta['format'] = "tsv"
            result.meta['message'] = None
            self.output(result)
            return
        except api_exceptions.InvalidArgument as e:
            message = "\n" + bytes(e.message, "utf8").decode("unicode_escape") + "\n"
            click.secho(message=message, err=True, nl=True)
            self.logger.exception(e)
            sys.exit(1)
        except Exception as e:  # pylint: disable=broad-except
            click.secho(message="\n" + str(e) + "\n", err=True, nl=True)
            self.logger.exception(e)
            sys.exit(1)
 def run(self):
     """Runs the interface and waits for user input commands."""
     completer = WordCompleter([
         'show', 'name', 'layer', 'dump', 'layers', 'preconditions',
         'postconditions', 'executions', 'intercept', 'timestamp',
         'version', 'save', 'description', 'spoof', 'clear', 'back'
     ])
     # Initialization of the command history
     history = FileHistory(join(self._polym_path, '.tinterface_history'))
     session = PromptSession(history=history)
     while True:
         try:
             command = session.prompt(
                 HTML("<bold>PH:cap/<red>t%d</red> > </bold>" %
                      self._index),
                 completer=completer,
                 complete_style=CompleteStyle.READLINE_LIKE,
                 auto_suggest=AutoSuggestFromHistory(),
                 enable_history_search=True)
         except KeyboardInterrupt:
             self.exit_program()
             continue
         command = command.split(" ")
         if command[0] in self.EXIT:
             self.exit_program()
         elif command[0] in self.RET:
             break
         elif command[0] == "name":
             self._name(command)
         elif command[0] in ["dump", "d"]:
             self._dump(command)
         elif command[0] in ["layer", "l"]:
             self._layer(command)
         elif command[0] in ['precs', 'preconditions']:
             self._conditions(command, 'preconditions')
         elif command[0] in ['posts', 'postconditions']:
             self._conditions(command, 'postconditions')
         elif command[0] in ['execs', 'executions']:
             self._conditions(command, 'executions')
         elif command[0] in ["show", "s"]:
             self._show(command)
         elif command[0] in ["intercept", "i"]:
             self._intercept(command)
         elif command[0] in ["layers", "ls"]:
             self._layers(command)
         elif command[0] == "timestamp":
             print(self._t.timestamp, '\n')
         elif command[0] == "version":
             self._version(command)
         elif command[0] in ['desc', 'description']:
             self._description(command)
         elif command[0] == "save":
             self._save(command)
         elif command[0] in ["spoof"]:
             self._spoof(command)
         elif command[0] == "clear":
             Interface._clear()
         elif command[0] == "":
             continue
         else:
             Interface._wrong_command()
Beispiel #27
0
class Console(code.InteractiveConsole):

    # This value is used as the `input` arg when initializing `prompt_toolkit.PromptSession`.
    # During testing there is a conflict with how pytest supresses stdin/out, so stdin is
    # replaced with `prompt_toolkit.input.defaults.create_pipe_input`
    prompt_input = None

    def __init__(self, project=None, extra_locals=None):
        """
        Launch the Brownie console.

        Arguments
        ---------
        project : `Project`, optional
            Active Brownie project to include in the console's local namespace.
        extra_locals: dict, optional
            Additional variables to add to the console namespace.
        """
        console_settings = CONFIG.settings["console"]

        locals_dict = dict((i, getattr(brownie, i)) for i in brownie.__all__)
        locals_dict.update(
            _dir=dir, dir=self._dir, exit=_Quitter("exit"), quit=_Quitter("quit"), _console=self
        )

        if project:
            project._update_and_register(locals_dict)

        # only make GUI available if Tkinter is installed
        try:
            Gui = importlib.import_module("brownie._gui").Gui
            locals_dict["Gui"] = Gui
        except ModuleNotFoundError:
            pass

        if extra_locals:
            locals_dict.update(extra_locals)

        # create prompt session object
        history_file = str(_get_data_folder().joinpath(".history").absolute())
        kwargs = {}
        if console_settings["show_colors"]:
            kwargs.update(
                lexer=PygmentsLexer(PythonLexer),
                style=style_from_pygments_cls(get_style_by_name(console_settings["color_style"])),
                include_default_pygments_style=False,
            )
        if console_settings["auto_suggest"]:
            kwargs["auto_suggest"] = ConsoleAutoSuggest(self, locals_dict)
        if console_settings["completions"]:
            kwargs["completer"] = ConsoleCompleter(self, locals_dict)
        if console_settings["editing_mode"]:
            kwargs["editing_mode"] = EditingMode(console_settings["editing_mode"].upper())

        self.compile_mode = "single"
        self.prompt_session = PromptSession(
            history=SanitizedFileHistory(history_file, locals_dict),
            input=self.prompt_input,
            key_bindings=KeyBindings(),
            **kwargs,
        )

        # add custom bindings
        key_bindings = self.prompt_session.key_bindings
        key_bindings.add(Keys.BracketedPaste)(self.paste_event)

        key_bindings.add("c-i")(self.tab_event)
        key_bindings.get_bindings_for_keys(("c-i",))[-1].filter = lambda: not self.tab_filter()

        # modify default bindings
        key_bindings = load_key_bindings()
        key_bindings.get_bindings_for_keys(("c-i",))[-1].filter = self.tab_filter

        if console_settings["auto_suggest"]:
            # remove the builtin binding for auto-suggest acceptance
            key_bindings = self.prompt_session.app.key_bindings
            accept_binding = key_bindings.get_bindings_for_keys(("right",))[0]
            key_bindings._bindings2.remove(accept_binding.handler)

        # this is required because of a pytest conflict when using the debugging console
        if sys.platform == "win32":
            import colorama

            colorama.init()

        super().__init__(locals_dict)

    def _dir(self, obj=None):
        # console dir method, for simplified and colorful output
        if obj is None:
            results = [(k, v) for k, v in self.locals.items() if not k.startswith("_")]
        elif hasattr(obj, "__console_dir__"):
            results = [(i, getattr(obj, i)) for i in obj.__console_dir__]
        else:
            results = [(i, getattr(obj, i)) for i in dir(obj) if not i.startswith("_")]
        results = sorted(results, key=lambda k: k[0])
        self.write(f"[{f'{color}, '.join(_dir_color(i[1]) + i[0] for i in results)}{color}]\n")

    def _console_write(self, obj):
        text = repr(obj)
        try:
            if obj and isinstance(obj, dict):
                text = color.pretty_dict(obj)
            elif obj and isinstance(obj, (tuple, list, set)):
                text = color.pretty_sequence(obj)
        except (SyntaxError, NameError):
            pass
        if CONFIG.settings["console"]["show_colors"]:
            text = color.highlight(text)
        self.write(text)

    def interact(self, *args, **kwargs):
        # temporarily modify mode so that container repr's display correctly for console
        cli_mode = CONFIG.argv["cli"]
        CONFIG.argv["cli"] = "console"
        try:
            super().interact(*args, **kwargs)
        finally:
            CONFIG.argv["cli"] = cli_mode

    def raw_input(self, prompt=""):
        return self.prompt_session.prompt(prompt)

    def showsyntaxerror(self, filename):
        tb = color.format_tb(sys.exc_info()[1])
        self.write(tb + "\n")

    def showtraceback(self):
        tb = color.format_tb(sys.exc_info()[1], start=1)
        self.write(tb + "\n")

    def resetbuffer(self):
        # reset the input buffer and parser cache
        _parser_cache.clear()
        return super().resetbuffer()

    def runsource(self, source, filename="<input>", symbol="single"):
        mode = self.compile_mode
        self.compile_mode = "single"

        try:
            code = self.compile(source, filename, mode)
        except (OverflowError, SyntaxError, ValueError):
            self.showsyntaxerror(filename)
            return False

        if code is None:
            # multiline statement
            return True

        try:
            self.compile(source, filename, "eval")
            code = self.compile(f"__ret_value__ = {source}", filename, "exec")
        except Exception:
            pass
        self.runcode(code)
        if "__ret_value__" in self.locals and self.locals["__ret_value__"] is not None:
            self._console_write(self.locals["__ret_value__"])
            del self.locals["__ret_value__"]
        return False

    def paste_event(self, event):
        # pasting multiline data temporarily switches to multiline mode
        data = event.data
        data = data.replace("\r\n", "\n")
        data = data.replace("\r", "\n")

        if "\n" in data:
            self.compile_mode = "exec"
        event.current_buffer.insert_text(data)

    def tab_event(self, event):
        # for multiline input, pressing tab at the start of a new line adds four spaces
        event.current_buffer.insert_text("    ")

    def tab_filter(self):
        # detect multiline input with no meaningful text on the current line
        return not self.buffer or self.prompt_session.app.current_buffer.text.strip()
Beispiel #28
0
async def repl() -> None:
    """
    Provides an interactive REPL for sending and receiving LWP3 messages.
    """
    os.makedirs(history_file.parent, exist_ok=True)
    session = PromptSession(history=FileHistory(history_file))

    def match_lwp3_uuid(dev: BLEDevice, adv: AdvertisementData) -> None:
        if LWP3_HUB_SERVICE_UUID.lower() not in adv.service_uuids:
            return False

        mfg_data = adv.manufacturer_data[LEGO_CID]
        button, kind, cap, last_net, status, opt = struct.unpack(
            "<6B", mfg_data)
        button = bool(button)
        kind = HubKind(kind)
        cap = Capabilities(cap)
        last_net = LastNetwork(last_net)
        status = Status(status)
        logger.debug(
            "button: %s, kind: %s, cap: %s, last net: %s, status: %s, option: %s",
            button,
            kind,
            cap,
            last_net,
            status,
            opt,
        )

        return True

    logger.info("scanning...")

    device = await BleakScanner.find_device_by_filter(match_lwp3_uuid)

    if device is None:
        logger.error("timed out")
        return

    logger.info("found device")

    def handle_disconnect(client: BleakClient):
        logger.info("disconnected")

    async with BleakClient(device,
                           disconnected_callback=handle_disconnect) as client:
        logger.info("connected")

        def handle_notify(handle, value):
            try:
                msg = parse_message(value)
            except Exception as ex:
                logger.warning("failed to parse message: %s",
                               value,
                               exc_info=ex)
            else:
                logger.info("received: %s", msg)

        await client.start_notify(LWP3_HUB_CHARACTERISTIC_UUID, handle_notify)

        # welcome is delayed to allow initial log messages to settle.
        async def welcome():
            await asyncio.sleep(1)
            print(
                "Type message and press ENTER to send. Press CTRL+D to exit.")

        asyncio.ensure_future(welcome())

        while True:
            with patch_stdout():
                try:
                    result = await session.prompt_async(">>> ")
                except KeyboardInterrupt:
                    # CTRL+C ignores the line
                    continue
                except EOFError:
                    # CTRL+D exits the program
                    break
            try:
                msg = eval(result, _eval_pool)
                if not isinstance(msg, AbstractMessage):
                    raise ValueError("not a message object")
            except Exception:
                logger.exception("bad input:")
            else:
                logger.info("sending: %s", msg)
                await client.write_gatt_char(LWP3_HUB_CHARACTERISTIC_UUID,
                                             bytes(msg))

        logger.info("disconnecting...")
Beispiel #29
0
class QuestionCreator(object):
    intro_message_color = "yellow"

    def __init__(self,
                 question_folder: str,
                 creator_name: str = "Question Creator"):
        """Initializer for Question Creator Obj

        Args:
            question_folder: The folder which the question yaml lives in
            creator_name: The name of the question creator
        """
        self.question_folder = question_folder
        self.creator_name = creator_name
        self.bindings = KeyBindings()
        self.quiz_id_prompt_session = PromptSession(key_bindings=self.bindings)
        self.question_prompt_session = PromptSession(
            key_bindings=self.bindings)
        self.amount_of_incorrect_answer_session = PromptSession(
            key_bindings=self.bindings)
        self.incorrect_answer_session = PromptSession(
            key_bindings=self.bindings)
        self.correct_answer_session = PromptSession(key_bindings=self.bindings)

        @self.bindings.add(
            'c-q'
        )  # This just makes the program exit nice when the user holds down control and Q
        def _(event):
            event.app.exit()

    def run(self):
        """Runs the app
        """
        self.print_intro_message()
        quiz_id = self.request_quiz_id()
        print("\n")
        question_file = self.get_quiz_file(quiz_id)
        go_again = True
        while go_again is True:
            question = self.ask_for_question()
            print("Saved Question")
            save_question_to_question_file(
                question, f"{self.question_folder}{question_file}")
            go_again = self.ask_if_go_again()

    def print_intro_message(self):
        """Prints the introduction message
        """
        print(figlet_format(self.creator_name))
        print("Press Control + Q at any time to quit")
        print("\n")

    def request_quiz_id(self):
        """Runs the prompts for getting the quiz id the user wishes to work with=
        """
        available_quizzes_list = get_quiz_files(
            self.question_folder)  # First get the applicable quiz files
        striped_available_quizzes_list = [
            s[:s.rindex(".")] for s in available_quizzes_list
        ]  # Then strip the endings
        available_quizzes_string = ", ".join(
            striped_available_quizzes_list
        )  # Join them to print which ones are available

        print(f"Available Quizzes: {available_quizzes_string}")
        quiz_id_completer = WordCompleter(striped_available_quizzes_list)
        quiz_id_validator = QuizIdValidator(striped_available_quizzes_list)
        quiz_id = self.quiz_id_prompt_session.prompt(
            "What quiz would you like to add questions to? ",
            completer=quiz_id_completer,
            validator=quiz_id_validator,
            validate_while_typing=False)
        return quiz_id

    def ask_for_question(self) -> dict:
        """Main holder for asking a question. Will prompt the user for all relevant information for the question
        Returns:
            The dictionary of the well formed question
        """
        question = self.ask_for_question_question()
        incorrect_answers_count = self.ask_for_incorrect_answer_amount()
        incorrect_answers = self.ask_for_incorrect_answers(
            incorrect_answers_count)
        correct_answer = self.ask_for_correct_answer()
        question_id = generate_unique_id()
        return form_question(question, question_id, incorrect_answers,
                             correct_answer)

    def ask_for_question_question(self):
        """Asks the user for their question
        """
        return str(self.question_prompt_session.prompt("Question: "))

    def ask_for_incorrect_answer_amount(self):
        """Asks the user for how many incorrect answers they can have
        """
        completer = WordCompleter(["1", "2", "3", "4"])
        return int(
            self.amount_of_incorrect_answer_session.prompt(
                "How many incorrect answers: ",
                completer=completer,
                validator=IncorrectAnswerValidator()))

    def ask_for_incorrect_answers(self, incorrect_answer_amount: int):
        """Ask for the users incorrect answers for the question

        Args:
            incorrect_answer_amount: The amount of incorrect answers

        Returns:
            A list of the users incorrect answers
        """
        incorrect_answers = []
        for count in range(
                1, incorrect_answer_amount +
                1):  # Loop for how may incorrect answers there is going to be
            incorrect_answers.append(
                str(
                    self.incorrect_answer_session.prompt(
                        f"> Incorrect Answer {count}: ")))
        return incorrect_answers

    def ask_for_correct_answer(self):
        """Asks the user for the correct answer

        Returns:
            The correct answer as a string
        """
        return str(self.correct_answer_session.prompt("Correct Answer: "))

    def get_quiz_file(self, quiz_id: str):
        """Gets the appropriate quiz_file based on id

        Args:
            quiz_id: The quiz id

        Returns:
            The filename of the appropriate quiz
        """
        quiz_files = get_quiz_files(self.question_folder)
        try:
            return [i for i in quiz_files if i.startswith(quiz_id)][0]
        except IndexError:
            print(
                f"Could not find {quiz_id} question file. It may have been deleted."
            )
            exit(1)

    def ask_if_go_again(self) -> bool:
        """Asks the user if they want to go again

        Returns:
            A boolean of true and false if they want to go again
        """
        allowed_go_again_values = ["yes", "y", "no", "n"]
        go_again_completer = WordCompleter(allowed_go_again_values)
        go_again_validator = GoAgainValidator(allowed_go_again_values)
        go_again: str = self.quiz_id_prompt_session.prompt(
            "Would you like to add another question? ",
            completer=go_again_completer,
            validator=go_again_validator,
            validate_while_typing=False)
        go_again = go_again.lower()
        if go_again == "yes" or go_again == "y":
            return True
        else:
            return False
Beispiel #30
0
from prompt_toolkit import PromptSession


def show_help():
    print("""Help
--------
quit - quit this application
exit - exit from this application
eval - evaluate
""")


s = PromptSession()

while True:
    try:
        cmd = s.prompt("Command: ")
        if cmd in {"q", "quit", "Quit", "exit", "Exit"}:
            break
        elif cmd in {"help", "Help", "?"}:
            show_help()
        elif cmd == "eval":
            print("42")
    except KeyboardInterrupt:
        continue
    except EOFError:
        break
Beispiel #31
0
class CMXDB():

    def __init__(self):
        self.connection = None
        self.proto = ''
        self.workspace = cfg.WORKSPACE
        self.prompt_str = 'cmxdb {} {}> '.format(self.workspace, self.proto)
        self.proto_db_path = None
        self.session = PromptSession(completer=my_completer)
        self.working = True

    def run(self):
        while self.working:
            try:
                text = self.session.prompt(self.prompt_str)
            except KeyboardInterrupt:
                continue    # Control-C pressed. Try again.
            except EOFError:
                break       # Control-D pressed.

            self.do_work(text.strip().lower())

    def connect_db(self, protocol=''):

        proto_db_path = (cfg.WS_PATH / cfg.WORKSPACE / protocol).with_suffix('.db')

        if proto_db_path.is_file():
            self.connection = sqlite3.connect(proto_db_path)
            self.proto = protocol
            return
        else:
            print('No database found for {}'.format(protocol))
        return

    def show_help(self, command):
        global genHelp
        global smbHelp
        global addHostHelp
        global addCredHelp

        if command == 'help' and self.proto == '':
            print(genHelp)
        elif command == 'help' and self.proto == 'smb':
            print(smbHelp)
        elif command.startswith('help add cred'):
            print(addCredHelp)
        elif command.startswith('help add host'):
            print(addHostHelp)
        elif command.startswith('help smb'):
            print(smbHelp)
        else:
            print("There's no help for you")

    def list_tables(self):

        if self.connection:
            with self.connection:
                try:
                    messages = self.connection.execute(
                        "SELECT name FROM sqlite_master WHERE type ='table' "
                        "AND name NOT LIKE 'sqlite_%';")
                except Exception as e:
                    print(repr(e))
                else:
                    for message in messages:
                        print(message)
        else:
            print('Not connected to a database yet')

    def do_back(self):

        if self.connection:
            self.proto = ''
            self.connection = None
        else:
            print('Nowhere to back out of')

    def show_creds(self, filterTerm=None, credType=None):

        pd.set_option('display.max_colwidth', 68)
        if self.connection:
            with self.connection:
                try:
                        # if we're returning a single credential by ID
                    if self.is_credential_valid(filterTerm):
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM users WHERE id=?", [filterTerm])))

                    elif credType:
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM users WHERE credtype=?", [credType])))

                    # if we're filtering by username
                    elif filterTerm and filterTerm != '':
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM users WHERE LOWER(username) "
                            "LIKE LOWER(?)", ['%{}%'.format(filterTerm)])))

                    # otherwise return all credentials
                    else:
                        print(colored(pd.read_sql_query(
                            "SELECT id, domain, username, password FROM users WHERE password IS NOT NULL AND password !='' ",
                            self.connection, index_col='id'), "green"))
                except Exception as e:
                    print(repr(e))
                else:
                    # for result in results:
                    print('')
        else:
            print('Not connected to a database yet')

    def show_users(self, filterTerm=None, credType=None):

        pd.set_option('display.max_colwidth', 68)
        if self.connection:
            with self.connection:
                try:
                        # if we're returning a single credential by ID
                    if self.is_credential_valid(filterTerm):
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM users WHERE id=?", [filterTerm])))

                    elif credType:
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM users WHERE credtype=?", [credType])))

                    # if we're filtering by username
                    elif filterTerm and filterTerm != '':
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM users WHERE LOWER(username) "
                            "LIKE LOWER(?)", ['%{}%'.format(filterTerm)])))

                    # otherwise return all credentials
                    else:
                        print(colored(pd.read_sql_query(
                            "SELECT id, domain, username FROM users",
                            self.connection, index_col='id'), "green"))
                except Exception as e:
                    print(repr(e))
                else:
                    # for result in results:
                    print('')
        else:
            print('Not connected to a database yet')

    def show_hosts(self, filterTerm=None, credType=None):

        pd.set_option('display.max_colwidth', 68)
        if self.connection:
            with self.connection:
                try:
                        # if we're returning a single credential by ID
                    if self.is_credential_valid(filterTerm):
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM computers WHERE id=? LIMIT 1", [filterTerm])))

                    elif credType:
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM computers WHERE credtype=?", [credType])))

                    # if we're filtering by username
                    elif filterTerm and filterTerm != '':
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM computers WHERE LOWER(hostname) "
                            "LIKE LOWER(?)", ['%{}%'.format(filterTerm)])))

                    # otherwise return all credentials
                    else:
                        print(colored(pd.read_sql_query(
                            "SELECT * FROM computers",
                            self.connection, index_col='id'), "green"))
                except Exception as e:
                    print(repr(e))
                else:
                    # for result in results:
                    print('')
        else:
            print('Not connected to a database yet')


    def is_credential_valid(self, credentialID):
        """
        Check if this credential ID is valid.
        """

        if self.connection:
            with self.connection:
                try:
                    results = self.connection.execute(
                        "SELECT * FROM users WHERE id=? AND password IS NOT "
                        "NULL LIMIT 1", [credentialID])
                except Exception as e:
                    print(repr(e))
                    return False
                else:
                    result = results.fetchall()
                    return len(result) > 0
        else:
            print('Not connected to a database yet')
            return False

    def do_work(self, command=''):

        if command == '':
            return

        if command.startswith('help ') or command == 'help':
            self.show_help(command)
            return

        if command == 'smb':
            self.connect_db('smb')
            return

        if command == 'list':
            self.list_tables()
            return

        if command == 'back':
            self.do_back()
            return

        if command == 'exit':
            self.working = False
            return

        if command == 'creds':
            self.show_creds()
            return

        if command == 'users':
            self.show_users()
            return

        if command == 'hosts':
            self.show_hosts()
            return

        else:
            print("Unknown Command")
            return
Beispiel #32
0
    def __init__(self, history: History = None):
        self._last_exception = None
        self._session = PromptSession(history=history)

        self.prompt = '> '
        self.prompt_style = Style.from_dict({'': 'bold'})
Beispiel #33
0
from prompt_toolkit import PromptSession
from prompt_toolkit import enums
from prompt_toolkit.completion import WordCompleter


def show_help():
    print("""Help
--------
quit - quit this application
exit - exit from this application
eval - evaluate
""")


c = WordCompleter(["quit", "exit", "help", "eval"], ignore_case=True)
s = PromptSession(completer=c, editing_mode=enums.EditingMode.EMACS)

while True:
    cmd = s.prompt("Command: ")
    if cmd in {"quit", "Quit", "exit", "Exit"}:
        break
    elif cmd in {"help", "Help", "?"}:
        show_help()
    elif cmd == "eval":
        print("42")
Beispiel #34
0
class Cmd:
    """
    A simple framework for writing typesafe line-oriented command interpreters.
    """
    def __init__(self, history: History = None):
        self._last_exception = None
        self._session = PromptSession(history=history)

        self.prompt = '> '
        self.prompt_style = Style.from_dict({'': 'bold'})

    # pylint: disable=no-self-use
    def get_command_prefixes(self):
        """
        Returns a mapping {method_command_prefix -> input_string_prefix}.
        input_string_prefix is a prefix of a command typed in the command line,
        method_command_prefix is the prefix for a matching command.

        If this function returns {'do_': ''}, then all methods whose names start
        with 'do_' will be available as commands with the same names, i.e.
        typing 'foo' will execute 'do_foo'.
        If it returned {'do_', '!'}, then one has to type '!foo' in order to
        execute 'do_foo'.
        """
        return {'do_': ''}

    def do_get_error(self):
        """
        Displays an exception thrown by last command.
        """
        if self._last_exception is None:
            print('no errors')
        else:
            traceback.print_exception(*self._last_exception)

    def do_exit(self):
        """Terminates the command loop."""
        print('exiting')
        return True

    # pylint: disable=invalid-name
    def do_EOF(self):
        """Terminates the command loop."""
        print('')
        return self.do_exit()

    # pylint: disable=arguments-differ
    def do_help(self,
                topic: str = ''):
        """
        Displays a description of given command or lists all available commands.
        """
        cmds = self._get_all_commands()

        if not topic:
            print('available commands: %s' % (' '.join(sorted(cmds)),))
            return

        try:
            handler = cmds.choose(topic, verbose=True)
            print(handler.help)
        except InvalidInput:
            print('no such command: %s' % (topic,))
            print('available commands: %s' % (' '.join(sorted(cmds)),))

    def _get_all_commands(self) -> CommandsDict:
        """Returns all defined commands."""
        import types

        def unbind(f):
            """
            Returns the base function if the argument is a bound one.

            https://bugs.python.org/msg166144
            """
            if not callable(f):
                raise TypeError('%s is not callable' % (repr(f),))

            self = getattr(f, '__self__', None)
            if (self is not None
                    and not isinstance(self, types.ModuleType)
                    and not isinstance(self, type)):
                if hasattr(f, '__func__'):
                    return f.__func__
                return getattr(type(f.__self__), f.__name__)

            return f

        members = inspect.getmembers(self)
        prefixes = self.get_command_prefixes()
        commands = CommandsDict()

        for name, handler in members:
            if not callable(handler):
                continue
            for prefix, substitution in prefixes.items():
                if name.startswith(prefix):
                    assert substitution + name not in commands
                    cmd_name = substitution + name[len(prefix):]
                    commands[cmd_name] = Command(name=cmd_name, handler=unbind(handler))

        return commands

    def emptyline(self):
        """
        Method called whenever the user enters an empty line.
        """

    def default(self, cmdline):
        """
        Interprets CMDLINE as a command and executes it.
        """
        try:
            if not cmdline:
                return self.emptyline()

            invoker = CommandInvoker(self._get_all_commands())
            return invoker.invoke(self, cmdline=CommandLine(cmdline))
        # it's a bit too ruthless to terminate on every single broken command
        # pylint: disable=broad-except
        except Exception as e:
            self._last_exception = sys.exc_info()
            print('%s (try "get_error" for details)' % e)
        else:
            self._last_exception = None

    def onecmd(self, cmdline):
        """
        Interprets CMDLINE as a command and executes it.
        """
        return self.default(cmdline)

    def cmdloop(self):
        """
        Interprets commands read from stdin until a shutdown is requested or
        EOF encountered.
        """
        completer = Completer(self._get_all_commands())
        try:
            while True:
                if os.isatty(sys.stdin.fileno()):
                    with patch_stdout():
                        cmd = self._session.prompt(self.prompt, completer=completer, style=self.prompt_style)
                else:
                    cmd = input(self.prompt)

                self.onecmd(cmd)
        except EOFError:
            pass
Beispiel #35
0
    async def loop(self):
        """Event loop for panctl."""
        promptsession = PromptSession("panctl> ", completer=self.completer)

        while True:
            with patch_stdout():
                try:
                    if PTK2:
                        result = await promptsession.prompt(async_=True)
                    else:
                        result = await promptsession.prompt_async()
                except EOFError:
                    break

            if not result:
                continue

            parser = PanctlParser(self.commands)

            try:
                args = parser.parse_args(result.split())
            except ParseError:
                continue

            command = args.subcommand

            if command == "list-servers":
                self.list_servers()

            if command == "help":
                self.show_help(args.command)

            elif command == "import-keys":
                self.own_message_ids.append(
                    self.ctl.ImportKeys(args.pan_user, args.path,
                                        args.passphrase))

            elif command == "export-keys":
                self.own_message_ids.append(
                    self.ctl.ExportKeys(args.pan_user, args.path,
                                        args.passphrase))

            elif command == "send-anyways":
                self.own_message_ids.append(
                    self.ctl.SendAnyways(args.pan_user, args.room_id))

            elif command == "cancel-sending":
                self.own_message_ids.append(
                    self.ctl.CancelSending(args.pan_user, args.room_id))

            elif command == "list-devices":
                self.list_devices(args)

            elif command == "verify-device":
                self.own_message_ids.append(
                    self.devices.Verify(args.pan_user, args.user_id,
                                        args.device_id))

            elif command == "unverify-device":
                self.own_message_ids.append(
                    self.devices.Unverify(args.pan_user, args.user_id,
                                          args.device_id))

            elif command == "blacklist-device":
                self.own_message_ids.append(
                    self.devices.Blacklist(args.pan_user, args.user_id,
                                           args.device_id))

            elif command == "unblacklist-device":
                self.own_message_ids.append(
                    self.devices.Unblacklist(args.pan_user, args.user_id,
                                             args.device_id))

            elif command == "start-verification":
                self.own_message_ids.append(
                    self.devices.StartKeyVerification(args.pan_user,
                                                      args.user_id,
                                                      args.device_id))

            elif command == "cancel-verification":
                self.own_message_ids.append(
                    self.devices.CancelKeyVerification(args.pan_user,
                                                       args.user_id,
                                                       args.device_id))

            elif command == "accept-verification":
                self.own_message_ids.append(
                    self.devices.AcceptKeyVerification(args.pan_user,
                                                       args.user_id,
                                                       args.device_id))

            elif command == "confirm-verification":
                self.own_message_ids.append(
                    self.devices.ConfirmKeyVerification(
                        args.pan_user, args.user_id, args.device_id))

            elif command == "continue-keyshare":
                self.own_message_ids.append(
                    self.devices.ContinueKeyShare(args.pan_user, args.user_id,
                                                  args.device_id))

            elif command == "cancel-keyshare":
                self.own_message_ids.append(
                    self.devices.CancelKeyShare(args.pan_user, args.user_id,
                                                args.device_id))
Beispiel #36
0
        def _process_input(self, reactor):
            if not self._quiet:
                self._print_startup_message()

            while self._ready.wait(0.5) != True:
                if not reactor.is_running():
                    return

            while True:
                expression = ""
                line = ""
                while len(expression) == 0 or line.endswith("\\"):
                    if not reactor.is_running():
                        return

                    prompt = "[%s]" % self._prompt_string + "-> " if len(expression) == 0 else "... "

                    pending_eval = self._pending_eval
                    if pending_eval is not None:
                        if len(pending_eval) > 0:
                            expression = pending_eval.pop(0)
                            if not self._quiet:
                                self._print(prompt + expression)
                        else:
                            self._pending_eval = None
                    else:
                        if self._quiet:
                            self._exit_status = 0 if self._errors == 0 else 1
                            return

                        try:
                            if self._have_terminal and not self._plain_terminal:
                                self._cli = PromptSession(lexer=PygmentsLexer(JavascriptLexer),
                                                          history=self._history, completer=self._completer)

                                line = self._cli.prompt(prompt)
                            else:
                                line = self._dumb_stdin_reader.read_line(prompt)
                                self._print(line)
                        except EOFError:
                            if not self._have_terminal and os.environ.get("TERM", '') != "dumb":
                                while not self._stopping.wait(1):
                                    pass
                            return
                        except KeyboardInterrupt:
                            line = ""
                            if not self._have_terminal:
                                sys.stdout.write("\n" + prompt)
                            continue
                        if len(line.strip()) > 0:
                            if len(expression) > 0:
                                expression += "\n"
                            expression += line.rstrip("\\")

                if expression.endswith("?"):
                    try:
                        self._print_help(expression)
                    except JavaScriptError as e:
                        error = e.error
                        self._print(Fore.RED + Style.BRIGHT + error['name'] + Style.RESET_ALL + ": " + error['message'])
                    except frida.InvalidOperationError:
                        return
                elif expression.startswith("%"):
                    self._do_magic(expression[1:].rstrip())
                elif expression in ("exit", "quit", "q"):
                    return
                elif expression == "help":
                    self._print("Help: #TODO :)")
                else:
                    if not self._eval_and_print(expression):
                        self._errors += 1
Beispiel #37
0
        "loaded" if cfg["iptables"] else "missing",
        "loaded" if cfg["ipaddrs"] else "missing",
        "loaded" if cfg["iproutes"] else "missing",
        "loaded" if cfg["ipsets"] else "missing",
        cfg["packet"].source, cfg["packet"].sport,
        cfg["packet"].dest, cfg["packet"].dport,
    )
    return text

cmd_completer = WordCompleter([
    'load-dir', 'load-iptables', 'load-ipaddrs', 'load-iproutes', 'load-ipsets',
    'set-source', 'set-dest', 'set-sport', 'set-dport',
    'run-incomming-packet', 'run-localgen-packet', 'exit',
], ignore_case=True)

session = PromptSession()

if __name__ == '__main__':
    init(autoreset=True)
    while True:
        input = session.prompt('> ', bottom_toolbar=bottom_statusbar, completer=merge_completers([PathCompleter(min_input_len=1), cmd_completer]))
        if not input.split():
            continue
        if input.split()[0] == "exit":
            break
        if input.split()[0] == "load-localhost":
            print("not implemented")
            continue
        if input.split()[0] == "load-dir":
            try:
                cfg["iptables"] = ParseIPTables(input.split()[1] + r"/iptables.txt")
Beispiel #38
0
def implant_command_loop(implant_id, user):
    while (True):
        try:
            style = Style.from_dict({
                '': '#80d130',
            })
            session = PromptSession(history=FileHistory('%s/.implant-history' %
                                                        PoshProjectDirectory),
                                    auto_suggest=AutoSuggestFromHistory(),
                                    style=style)
            implant_id_orig = implant_id
            if ("-" in implant_id) or ("all" in implant_id) or (","
                                                                in implant_id):
                print(Colours.GREEN)
                prompt_commands = POSH_COMMANDS
                command = session.prompt("%s> " % implant_id,
                                         completer=FirstWordFuzzyWordCompleter(
                                             prompt_commands, WORD=True))
                if command == "back" or command == 'clear':
                    do_back(user, command)
                    return
            else:
                implant = get_implantbyid(implant_id)
                if not implant:
                    print_bad("Unrecognised implant id or command: %s" %
                              implant_id)
                    input("Press Enter to continue...")
                    clear()
                    return
                prompt_commands = POSH_COMMANDS
                if implant.Pivot.startswith('Python'):
                    prompt_commands = PY_COMMANDS
                if implant.Pivot.startswith('C#'):
                    prompt_commands = SHARP_COMMANDS
                if 'PB' in implant.Pivot:
                    style = Style.from_dict({
                        '': '#008ECC',
                    })
                    session = PromptSession(
                        history=FileHistory('%s/.implant-history' %
                                            PoshProjectDirectory),
                        auto_suggest=AutoSuggestFromHistory(),
                        style=style)
                    prompt_commands = SHARP_COMMANDS
                    print(Colours.BLUE)
                else:
                    print(Colours.GREEN)
                print("%s\\%s @ %s (PID:%s)" % (implant.Domain, implant.User,
                                                implant.Hostname, implant.PID))
                command = session.prompt(
                    "%s %s> " %
                    (get_implant_type_prompt_prefix(implant_id), implant_id),
                    completer=FirstWordFuzzyWordCompleter(prompt_commands,
                                                          WORD=True))
                if command == "back" or command == 'clear':
                    do_back(user, command)
                    return

            # if "all" run through all implants get_implants()
            if implant_id == "all":
                if command == "back" or command == 'clear':
                    do_back(user, command)
                    return
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implants_split = get_implants()
                if implants_split:
                    for implant_details in implants_split:
                        # if "\n" in command run each command individually or ask the question if that's what they want to do
                        if "\n" in allcommands:
                            if ri.lower() == "y" or ri == "":
                                commands = allcommands.split('\n')
                                for command in commands:
                                    run_implant_command(
                                        command, implant_details.RandomURI,
                                        implant_id_orig, user)
                            else:
                                run_implant_command(command,
                                                    implant_details.RandomURI,
                                                    implant_id_orig, user)
                        else:
                            run_implant_command(command,
                                                implant_details.RandomURI,
                                                implant_id_orig, user)

            # if "separated list" against single uri
            elif "," in implant_id:
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implant_split = implant_id.split(",")
                for split_implant_id in implant_split:
                    implant_randomuri = get_randomuri(split_implant_id)
                    # if "\n" in command run each command individually or ask the question if that's what they want to do
                    if "\n" in allcommands:
                        if ri.lower() == "y" or ri == "":
                            commands = allcommands.split('\n')
                            for command in commands:
                                run_implant_command(command, implant_randomuri,
                                                    implant_id_orig, user)
                        else:
                            run_implant_command(command, implant_randomuri,
                                                implant_id_orig, user)
                    else:
                        run_implant_command(command, implant_randomuri,
                                            implant_id_orig, user)

            # if "range" against single uri
            elif "-" in implant_id:
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implant_split = implant_id.split("-")
                for range_implant_id in range(int(implant_split[0]),
                                              int(implant_split[1]) + 1):
                    try:
                        implant_randomuri = get_randomuri(range_implant_id)
                        # if "\n" in command run each command individually or ask the question if that's what they want to do
                        if "\n" in allcommands:
                            if ri.lower() == "y" or ri == "":
                                commands = allcommands.split('\n')
                                for command in commands:
                                    run_implant_command(
                                        command, implant_randomuri,
                                        implant_id_orig, user)
                            else:
                                run_implant_command(command, implant_randomuri,
                                                    implant_id_orig, user)
                        else:
                            run_implant_command(command, implant_randomuri,
                                                implant_id_orig, user)
                    except Exception:
                        print_bad("Unknown ImplantID")

            # else run against single uri
            else:
                allcommands = command
                if "\n" in command:
                    ri = input(
                        "Do you want to run commands separately? (Y/n) ")
                implant_randomuri = get_randomuri(implant_id)
                # if "\n" in command run each command individually or ask the question if that's what they want to do
                if "\n" in allcommands:
                    if ri.lower() == "y" or ri == "":
                        commands = allcommands.split('\n')
                        for command in commands:
                            run_implant_command(command, implant_randomuri,
                                                implant_id_orig, user)
                    else:
                        run_implant_command(command, implant_randomuri,
                                            implant_id_orig, user)
                else:
                    run_implant_command(command, implant_randomuri,
                                        implant_id_orig, user)

        except KeyboardInterrupt:
            continue
        except EOFError:
            new_c2_message("%s logged off." % user)
            sys.exit(0)
        except Exception as e:
            traceback.print_exc()
            print_bad(
                f"Error running against the selected implant ID, ensure you have typed the correct information: {e}"
            )
            return
Beispiel #39
0
class CmdLoop:

    def __init__(self):
        self.name = 'main'
        self.prompt_session = PromptSession(
            'ST ≫ ',
            bottom_toolbar=bottom_toolbar,
            auto_suggest=AutoSuggestFromHistory(),
            enable_history_search=True,
            # rprompt=get_rprompt,
            # style=rprompt_style
        )

        self.contexts = [
            Listeners(self.prompt_session),
            Sessions(self.prompt_session),
            Modules(self.prompt_session),
            Stagers(self.prompt_session)
        ]

        self.prompt_session.completer = WordCompleter([ctx.name for ctx in self.contexts] + ['exit'], ignore_case=True)
        self.prompt_session.contexts = self.contexts

        self.current_context = self

    def switched_context(self, result):
        for ctx in self.contexts:
            if result == ctx.name:
                self.prompt_session.message = ctx.prompt
                self.prompt_session.completer = ctx.completer
                self.current_context = ctx
                return True
        return False

    def parse_result(self, result):
        if len(result):
            if not self.switched_context(result):
                command = split(result)
                try:
                    logging.debug(f"command: {command[0]} args: {command[1:]} ctx: {self.current_context.name}")

                    bound_cmd_handler = functools.partial(getattr(self.current_context, command[0]), args=command[1:])
                    run_in_terminal(bound_cmd_handler)
                except AttributeError:
                    print_bad(f"Unknown command '{command[0]}'")
                    if args['--debug']:
                        traceback.print_exc()
                except DocoptExit as e:
                    print(str(e))
                except SystemExit:
                    pass

    def run_resource_file(self):
        with open(args['--resource-file']) as resource_file:
            for cmd in resource_file:
                result = self.prompt_session.prompt(accept_default=True, default=cmd.strip())
                self.parse_result(result)

    def __call__(self):
        if args['--resource-file']:
            self.run_resource_file()

        while True:
            result = self.prompt_session.prompt()
            if result == 'exit':
                break
            elif result == 'help':
                table_data = [
                    ["Command", "Description"]
                ]

                try:
                    for cmd in self.current_context._cmd_registry:
                        table_data.append([cmd, getattr(self.current_context, cmd).__doc__.split('\n', 2)[1].strip()])

                    for menu in self.contexts:
                        if menu.name != self.current_context.name:
                            table_data.append([menu.name, menu.description])
                except AttributeError:
                    for menu in self.contexts:
                        table_data.append([menu.name, menu.description])

                table = AsciiTable(table_data)
                print(table.table)
                continue

            self.parse_result(result)
Beispiel #40
0
def handle_pbind_command(command, user, randomuri, implant_id):

    # convert randomuri to parent randomuri
    oldrandomuri = randomuri
    p = get_implantdetails(randomuri)
    newimplant_id = re.search(r'(?<=\s)\S*', p.Label).group()
    if newimplant_id is not None:
        randomuri = get_randomuri(newimplant_id)

    # alias mapping
    for alias in cs_alias:
        if alias[0] == command[:len(command.rstrip())]:
            command = alias[1]

    # alias replace
    for alias in cs_replace:
        if command.startswith(alias[0]):
            command = command.replace(alias[0], alias[1])

    original_command = command
    command = command.strip()

    run_autoloads_sharp(command, randomuri, user, isPBind=True)

    if command.startswith("searchhistory"):
        searchterm = (command).replace("searchhistory ", "")
        with open('%s/.implant-history' % PoshProjectDirectory) as hisfile:
            for line in hisfile:
                if searchterm in line.lower():
                    print(Colours.GREEN + line.replace("+", ""))

    elif command.startswith("searchhelp"):
        searchterm = (command).replace("searchhelp ", "")
        helpful = sharp_help.split('\n')
        for line in helpful:
            if searchterm in line.lower():
                print(Colours.GREEN + line)

    elif command.startswith("upload-file"):
        source = ""
        destination = ""
        if command == "upload-file":
            style = Style.from_dict({
                '': '#80d130',
            })
            session = PromptSession(history=FileHistory('%s/.upload-history' %
                                                        PoshProjectDirectory),
                                    auto_suggest=AutoSuggestFromHistory(),
                                    style=style)
            try:
                source = session.prompt("Location file to upload: ",
                                        completer=FilePathCompleter(
                                            PayloadsDirectory, glob="*"))
                source = PayloadsDirectory + source
            except KeyboardInterrupt:
                return
            while not os.path.isfile(source):
                print("File does not exist: %s" % source)
                source = session.prompt("Location file to upload: ",
                                        completer=FilePathCompleter(
                                            PayloadsDirectory, glob="*"))
                source = PayloadsDirectory + source
            destination = session.prompt("Location to upload to: ")
        else:
            args = argp(command)
            source = args.source
            destination = args.destination
        try:
            destination = destination.replace("\\", "\\\\")
            print("")
            print("Uploading %s to %s" % (source, destination))
            uploadcommand = f"upload-file {source} {destination}"
            new_task(f"pbind-command {uploadcommand}", user, randomuri)
        except Exception as e:
            print_bad("Error with source file: %s" % e)
            traceback.print_exc()

    elif command.startswith("unhide-implant"):
        unhide_implant(oldrandomuri)

    elif command.startswith("hide-implant"):
        kill_implant(oldrandomuri)

    elif command.startswith("inject-shellcode"):
        params = re.compile("inject-shellcode", re.IGNORECASE)
        params = params.sub("", command)
        style = Style.from_dict({
            '': '#80d130',
        })
        session = PromptSession(history=FileHistory('%s/.shellcode-history' %
                                                    PoshProjectDirectory),
                                auto_suggest=AutoSuggestFromHistory(),
                                style=style)
        try:
            path = session.prompt("Location of shellcode file: ",
                                  completer=FilePathCompleter(
                                      PayloadsDirectory, glob="*.bin"))
            path = PayloadsDirectory + path
        except KeyboardInterrupt:
            return
        try:
            shellcodefile = load_file(path)
            if shellcodefile is not None:
                new_task(
                    "pbind-command run-exe Core.Program Core Inject-Shellcode %s%s #%s"
                    % (base64.b64encode(shellcodefile).decode("utf-8"), params,
                       os.path.basename(path)), user, randomuri)
        except Exception as e:
            print("Error loading file: %s" % e)

    elif command.startswith("migrate"):
        params = re.compile("migrate", re.IGNORECASE)
        params = params.sub("", command)
        migrate(randomuri, user, params)

    elif command == "kill-implant" or command == "exit":
        impid = get_implantdetails(randomuri)
        ri = input(
            "Are you sure you want to terminate the implant ID %s? (Y/n) " %
            impid.ImplantID)
        if ri.lower() == "n":
            print("Implant not terminated")
        if ri == "" or ri.lower() == "y":
            new_task("pbind-kill", user, randomuri)
            kill_implant(oldrandomuri)

    elif command == "sharpsocks":
        from random import choice
        allchar = string.ascii_letters
        channel = "".join(choice(allchar) for x in range(25))
        sharpkey = gen_key().decode("utf-8")
        sharpurls = get_sharpurls()
        sharpurls = sharpurls.split(",")
        sharpurl = select_item("HostnameIP", "C2Server")
        print(
            PoshInstallDirectory +
            "SharpSocks/SharpSocksServerCore -c=%s -k=%s --verbose -l=%s\r\n" %
            (channel, sharpkey, SocksHost) + Colours.GREEN)
        ri = input(
            "Are you ready to start the SharpSocks in the implant? (Y/n) ")
        if ri.lower() == "n":
            print("")
        if ri == "":
            new_task(
                "pbind-command run-exe SharpSocksImplantTestApp.Program SharpSocks -s %s -c %s -k %s -url1 %s -url2 %s -b 2000 --session-cookie ASP.NET_SessionId --payload-cookie __RequestVerificationToken"
                % (sharpurl, channel, sharpkey, sharpurls[0].replace(
                    "\"", ""), sharpurls[1].replace("\"", "")), user,
                randomuri)
        if ri.lower() == "y":
            new_task(
                "pbind-command run-exe SharpSocksImplantTestApp.Program SharpSocks -s %s -c %s -k %s -url1 %s -url2 %s -b 2000 --session-cookie ASP.NET_SessionId --payload-cookie __RequestVerificationToken"
                % (sharpurl, channel, sharpkey, sharpurls[0].replace(
                    "\"", ""), sharpurls[1].replace("\"", "")), user,
                randomuri)

    elif (command.startswith("stop-keystrokes")):
        new_task(
            "pbind-command run-exe Logger.KeyStrokesClass Logger %s" % command,
            user, randomuri)
        update_label("", randomuri)

    elif (command.startswith("start-keystrokes")):
        check_module_loaded("Logger.exe", randomuri, user)
        new_task(
            "pbind-command run-exe Logger.KeyStrokesClass Logger %s" % command,
            user, randomuri)
        update_label("KEYLOG", randomuri)

    elif (command.startswith("get-keystrokes")):
        new_task(
            "pbind-command run-exe Logger.KeyStrokesClass Logger %s" % command,
            user, randomuri)

    elif (command.startswith("get-screenshotmulti")):
        pwrStatus = get_powerstatusbyrandomuri(randomuri)
        if (pwrStatus is not None and pwrStatus[7]):
            ri = input(
                "[!] Screen is reported as LOCKED, do you still want to attempt a screenshot? (y/N) "
            )
            if ri.lower() == "n" or ri.lower() == "":
                return
        new_task(f"pbind-command {command}", user, randomuri)
        update_label("SCREENSHOT", randomuri)

    elif (command.startswith("get-screenshot")):
        pwrStatus = get_powerstatusbyrandomuri(randomuri)
        if (pwrStatus is not None and pwrStatus[7]):
            ri = input(
                "[!] Screen is reported as LOCKED, do you still want to attempt a screenshot? (y/N) "
            )
            if ri.lower() == "n" or ri.lower() == "":
                return
        new_task(f"pbind-command {command}", user, randomuri)

    elif (command == "get-powerstatus"):
        getpowerstatus(randomuri)
        new_task(
            "pbind-command run-dll PwrStatusTracker.PwrFrm PwrStatusTracker GetPowerStatusResult ",
            user, randomuri)

    elif (command == "getpowerstatus"):
        getpowerstatus(randomuri)
        new_task(
            "pbind-command run-dll PwrStatusTracker.PwrFrm PwrStatusTracker GetPowerStatusResult ",
            user, randomuri)

    elif (command.startswith("stop-powerstatus")):
        new_task(f"pbind-command {command}", user, randomuri)
        update_label("", randomuri)

    elif (command.startswith("stoppowerstatus")):
        new_task(f"pbind-command {command}", user, randomuri)
        update_label("", randomuri)

    elif (command.startswith("pslo")):
        new_task(f"pbind-{command}", user, randomuri)

    elif (command.startswith("run-exe SharpWMI.Program")
          ) and "execute" in command and "payload" not in command:
        style = Style.from_dict({'': '#80d130'})
        session = PromptSession(history=FileHistory('%s/.shellcode-history' %
                                                    PoshProjectDirectory),
                                auto_suggest=AutoSuggestFromHistory(),
                                style=style)
        try:
            path = session.prompt("Location of base64 vbs/js file: ",
                                  completer=FilePathCompleter(
                                      PayloadsDirectory, glob="*.b64"))
            path = PayloadsDirectory + path
        except KeyboardInterrupt:
            return
        if os.path.isfile(path):
            with open(path, "r") as p:
                payload = p.read()
            new_task("pbind-command %s payload=%s" % (command, payload), user,
                     randomuri)
        else:
            print_bad("Could not find file")

    elif (command.startswith("get-hash")):
        check_module_loaded("InternalMonologue.exe", randomuri, user)
        new_task(
            "pbind-command run-exe InternalMonologue.Program InternalMonologue",
            user, randomuri)

    elif (command.startswith("safetykatz")):
        new_task("pbind-command run-exe SafetyKatz.Program %s" % command, user,
                 randomuri)

    elif command.startswith("loadmoduleforce"):
        params = re.compile("loadmoduleforce ", re.IGNORECASE)
        params = params.sub("", command)
        new_task("pbind-loadmodule %s" % params, user, randomuri)

    elif command.startswith("loadmodule"):
        params = re.compile("loadmodule ", re.IGNORECASE)
        params = params.sub("", command)
        new_task("pbind-loadmodule %s" % params, user, randomuri)

    elif command.startswith("listmodules"):
        modules = os.listdir("%s/Modules/" % PoshInstallDirectory)
        modules = sorted(modules, key=lambda s: s.lower())
        print("")
        print("[+] Available modules:")
        print("")
        for mod in modules:
            if (".exe" in mod) or (".dll" in mod):
                print(mod)

    elif command.startswith("modulesloaded"):
        ml = get_implantdetails(randomuri)
        print(ml.ModsLoaded)
        new_task("pbind-command listmodules", user, randomuri)

    elif command == "help" or command == "?":
        print(sharp_help)

    elif command.startswith("beacon") or command.startswith(
            "set-beacon") or command.startswith("setbeacon"):
        new_sleep = command.replace('set-beacon ', '')
        new_sleep = new_sleep.replace('setbeacon ', '')
        new_sleep = new_sleep.replace('beacon ', '').strip()
        if not validate_sleep_time(new_sleep):
            print(Colours.RED)
            print(
                "Invalid sleep command, please specify a time such as 50s, 10m or 1h"
            )
            print(Colours.GREEN)
        else:
            new_task(f"pbind-command {command}", user, randomuri)

    else:
        if command:
            new_task(f"pbind-command {original_command}", user, randomuri)
        return
Beispiel #41
0
class TUI:
    def __init__(self):
        self.core = Core()
        self.session = PromptSession(reserve_space_for_menu=6)
        self.headless = False
        self.console = None
        self.table = None
        self.cfSlugs = None
        self.wowiSlugs = None
        self.completer = None
        self.os = platform.system()
        install()

    def start(self):
        # Check if headless mode was requested
        if len(sys.argv) == 2 and sys.argv[1].lower() == 'headless':
            self.headless = True
        self.setup_console()
        self.print_header()
        # Check if executable is in good location
        if not glob.glob('World*.app') and not glob.glob('Wow*.exe') or \
                not os.path.isdir(Path('Interface/AddOns')) or not os.path.isdir('WTF'):
            self.console.print('[bold red]This executable should be placed in the same directory where Wow.exe, '
                               'WowClassic.exe or World of Warcraft.app is located.[/bold red]\n\n')
            pause(self.headless)
            sys.exit(1)
        # Detect Classic client
        if os.path.basename(os.getcwd()) == '_classic_':
            self.core.clientType = 'wow_classic'
            set_terminal_title(f'CurseBreaker v{__version__} - Classic')
        # Check if client have write access
        try:
            with open('PermissionTest', 'w') as _:
                pass
            os.remove('PermissionTest')
        except IOError:
            self.console.print('[bold red]CurseBreaker doesn\'t have write rights for the current directory.\n'
                               'Try starting it with administrative privileges.[/bold red]\n\n')
            pause(self.headless)
            sys.exit(1)
        self.auto_update()
        self.core.init_config()
        self.setup_table()
        # Curse URI Support
        if len(sys.argv) == 2 and 'twitch://' in sys.argv[1]:
            try:
                self.c_install(sys.argv[1].strip())
            except Exception as e:
                self.handle_exception(e)
            timeout(self.headless)
            sys.exit(0)
        if len(sys.argv) == 2 and '.ccip' in sys.argv[1]:
            try:
                path = sys.argv[1].strip()
                self.c_install(self.core.parse_cf_xml(path))
                if os.path.exists(path):
                    os.remove(path)
            except Exception as e:
                self.handle_exception(e)
            timeout(self.headless)
            sys.exit(0)
        # CLI command
        if len(sys.argv) >= 2:
            command = ' '.join(sys.argv[1:]).split(' ', 1)
            if command[0].lower() == 'headless':
                pass
            elif getattr(self, f'c_{command[0].lower()}', False):
                try:
                    getattr(self, f'c_{command[0].lower()}')(command[1].strip() if len(command) > 1 else False)
                except Exception as e:
                    self.handle_exception(e)
                sys.exit(0)
            else:
                self.console.print('Command not found.')
                sys.exit(0)
        # Addons auto update
        if len(self.core.config['Addons']) > 0:
            if not self.headless:
                self.console.print('Automatic update of all addons will start in 5 seconds.\n'
                                   'Press any button to enter interactive mode.', highlight=False)
            starttime = time.time()
            keypress = None
            while True:
                if self.headless:
                    break
                elif kbhit():
                    keypress = getch()
                    break
                elif time.time() - starttime > 5:
                    break
            if not keypress:
                if not self.headless:
                    self.print_header()
                try:
                    self.c_update(None, True)
                    if self.core.backup_check():
                        self.setup_table()
                        self.console.print(f'\n[green]Backing up WTF directory{"!" if self.headless else ":"}[/green]')
                        self.core.backup_wtf(None if self.headless else self.console)
                    if self.core.config['WAUsername'] != 'DISABLED':
                        self.setup_table()
                        self.c_wa_update(None, False)
                except Exception as e:
                    self.handle_exception(e)
                self.console.print('')
                self.print_log()
                pause(self.headless)
                sys.exit(0)
        if self.headless:
            sys.exit(1)
        self.setup_completer()
        self.print_header()
        self.console.print('Use command [green]help[/green] or press [green]TAB[/green] to see a list of available comm'
                           'ands.\nCommand [green]exit[/green] or pressing [green]CTRL+D[/green] will close the applica'
                           'tion.\n\n')
        if len(self.core.config['Addons']) == 0:
            self.console.print('Command [green]import[/green] might be used to detect already installed addons.\n\n')
        # Prompt session
        while True:
            try:
                command = self.session.prompt(HTML('<ansibrightgreen>CB></ansibrightgreen> '), completer=self.completer)
            except KeyboardInterrupt:
                continue
            except EOFError:
                break
            else:
                command = command.split(' ', 1)
                if getattr(self, f'c_{command[0].lower()}', False):
                    try:
                        self.setup_table()
                        getattr(self, f'c_{command[0].lower()}')(command[1].strip() if len(command) > 1 else False)
                        self.setup_completer()
                    except Exception as e:
                        self.handle_exception(e)
                else:
                    self.console.print('Command not found.')

    def auto_update(self):
        if getattr(sys, 'frozen', False):
            try:
                if os.path.isfile(sys.executable + '.old'):
                    try:
                        os.remove(sys.executable + '.old')
                    except PermissionError:
                        pass
                payload = requests.get('https://api.github.com/repos/AcidWeb/CurseBreaker/releases/latest',
                                       headers=HEADERS).json()
                if 'name' in payload and 'body' in payload and 'assets' in payload:
                    remoteversion = payload['name']
                    changelog = payload['body']
                    url = None
                    for binary in payload['assets']:
                        if (self.os == 'Windows' and '.exe' in binary['name'])\
                                or (self.os == 'Darwin' and '.zip' in binary['name'])\
                                or (self.os == 'Linux' and '.gz' in binary['name']):
                            url = binary['browser_download_url']
                            break
                    if url and StrictVersion(remoteversion[1:]) > StrictVersion(__version__):
                        self.console.print('[green]Updating CurseBreaker...[/green]')
                        shutil.move(sys.executable, sys.executable + '.old')
                        payload = requests.get(url, headers=HEADERS)
                        if self.os == 'Darwin':
                            zipfile.ZipFile(io.BytesIO(payload.content)).extractall()
                        else:
                            with open(sys.executable, 'wb') as f:
                                if self.os == 'Windows':
                                    f.write(payload.content)
                                elif self.os == 'Linux':
                                    f.write(gzip.decompress(payload.content))
                        os.chmod(sys.executable, 0o775)
                        self.console.print(f'[bold green]Update complete! Please restart the application.[/bold green]'
                                           f'\n\n[green]Changelog:[/green]\n{changelog}\n\n')
                        self.print_log()
                        pause(self.headless)
                        sys.exit(0)
            except Exception as e:
                self.console.print(f'[bold red]Update failed!\n\nReason: {str(e)}[/bold red]\n\n')
                self.print_log()
                pause(self.headless)
                sys.exit(1)

    def handle_exception(self, e, table=True):
        if self.table.row_count > 1 and table:
            self.console.print(self.table)
        if getattr(sys, 'frozen', False):
            sys.tracebacklimit = 0
        if isinstance(e, list):
            for es in e:
                self.console.print(Traceback.from_exception(exc_type=es.__class__, exc_value=es,
                                                            traceback=es.__traceback__))
        else:
            self.console.print(Traceback.from_exception(exc_type=e.__class__, exc_value=e, traceback=e.__traceback__))

    def print_header(self):
        clear()
        if self.headless:
            self.console.print(f'[bold green]CurseBreaker[/bold green] [bold red]v{__version__}[/bold red] | '
                               f'[yellow]{datetime.now()}[/yellow]', highlight=False)
        else:
            self.console.print(Rule(f'[bold green]CurseBreaker[/bold green] [bold red]v{__version__}[/bold red]'))
            self.console.print('\n')

    def print_log(self):
        if self.headless:
            html = self.console.export_html(inline_styles=True, theme=HEADLESS_TERMINAL_THEME)
            with open('CurseBreaker.html', 'a+', encoding='utf-8') as log:
                log.write(html)

    def setup_console(self):
        if self.headless:
            self.console = Console(record=True)
            if self.os == 'Windows':
                window = windll.kernel32.GetConsoleWindow()
                if window:
                    windll.user32.ShowWindow(window, 0)
        elif 'WINDIR' in os.environ and 'WT_SESSION' not in os.environ:
            set_terminal_size(100, 50)
            windll.kernel32.SetConsoleScreenBufferSize(windll.kernel32.GetStdHandle(-11), wintypes._COORD(100, 200))
            self.console = Console(width=97)
        elif self.os == 'Darwin':
            set_terminal_size(100, 50)
            self.console = Console()
        else:
            self.console = Console()

    def setup_completer(self):
        if not self.cfSlugs or not self.wowiSlugs:
            # noinspection PyBroadException
            try:
                self.cfSlugs = pickle.load(gzip.open(io.BytesIO(
                    requests.get('https://storage.googleapis.com/cursebreaker/cfslugs.pickle.gz',
                                 headers=HEADERS).content)))
                self.wowiSlugs = pickle.load(gzip.open(io.BytesIO(
                    requests.get('https://storage.googleapis.com/cursebreaker/wowislugs.pickle.gz',
                                 headers=HEADERS).content)))
            except Exception:
                self.cfSlugs = []
                self.wowiSlugs = []
        commands = ['install', 'uninstall', 'update', 'force_update', 'wa_update', 'status', 'orphans', 'search',
                    'import', 'export', 'toggle_backup', 'toggle_dev', 'toggle_wa', 'set_wa_api', 'set_wa_wow_account',
                    'uri_integration', 'help', 'exit']
        addons = sorted(self.core.config['Addons'], key=lambda k: k['Name'].lower())
        for addon in addons:
            name = f'"{addon["Name"]}"' if ',' in addon["Name"] else addon["Name"]
            commands.extend([f'uninstall {name}', f'update {name}', f'force_update {name}', f'toggle_dev {name}',
                             f'status {name}'])
        for item in self.cfSlugs:
            commands.append(f'install cf:{item}')
        for item in self.wowiSlugs:
            commands.append(f'install wowi:{item}')
        commands.extend(['install ElvUI', 'install ElvUI:Dev', 'install Tukui', 'install SLE:Dev'])
        accounts = self.core.detect_accounts()
        for account in accounts:
            commands.append(f'set_wa_wow_account {account}')
        self.completer = WordCompleter(commands, ignore_case=True, sentence=True)

    def setup_table(self):
        self.table = Table(box=box.SQUARE)
        self.table.add_column('Status', header_style='bold white', justify='center')
        self.table.add_column('Name', header_style='bold white')
        self.table.add_column('Version', header_style='bold white')

    def c_install(self, args):
        if args:
            if args.startswith('-i '):
                args = args[3:]
                optignore = True
            else:
                optignore = False
            addons = [addon.strip() for addon in list(reader([args], skipinitialspace=True))[0]]
            with Progress('{task.completed}/{task.total}', '|', BarColumn(bar_width=None), '|',
                          auto_refresh=False, console=self.console) as progress:
                task = progress.add_task('', total=len(addons))
                while not progress.finished:
                    for addon in addons:
                        installed, name, version = self.core.add_addon(addon, optignore)
                        if installed:
                            self.table.add_row('[green]Installed[/green]', name, version)
                        else:
                            self.table.add_row('[bold black]Already installed[/bold black]', name, version)
                        progress.update(task, advance=1, refresh=True)
            self.console.print(self.table)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a comma-separated list of links as an arg'
                               'ument.\n\tOption [bold white]-i[/bold white] will disable the client version check.\n[b'
                               'old green]Supported URL:[/bold green]\n\thttps://www.curseforge.com/wow/addons/[[addon_'
                               'name]] [bold white]|[/bold white] cf:[[addon_name]]\n\thttps://www.wowinterface.com/dow'
                               'nloads/[[addon_name]] [bold white]|[/bold white] wowi:[[addon_id]]\n\thttps://www.tukui'
                               '.org/addons.php?id=[[addon_id]] [bold white]|[/bold white] tu:[[addon_id]]\n\thttps://w'
                               'ww.tukui.org/classic-addons.php?id=[[addon_id]] [bold white]|[/bold white] tuc:[[addon_'
                               'id]]\n\tElvUI [bold white]|[/bold white] ElvUI:Dev\n\tTukui\n\tSLE:Dev',
                               highlight=False)

    def c_uninstall(self, args):
        if args:
            addons = [addon.strip() for addon in list(reader([args], skipinitialspace=True))[0]]
            with Progress('{task.completed}/{task.total}', '|', BarColumn(bar_width=None), '|',
                          auto_refresh=False, console=self.console) as progress:
                task = progress.add_task('', total=len(addons))
                while not progress.finished:
                    for addon in addons:
                        name, version = self.core.del_addon(addon)
                        if name:
                            self.table.add_row(f'[bold red]Uninstalled[/bold red]', name, version)
                        else:
                            self.table.add_row(f'[bold black]Not installed[/bold black]', addon, '')
                        progress.update(task, advance=1, refresh=True)
            self.console.print(self.table)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a comma-separated list of addon names or '
                               'full links as an argument.\n[bold green]Supported URL:[/bold green]\n\thttps://www.curs'
                               'eforge.com/wow/addons/[[addon_name]]\n\thttps://www.wowinterface.com/downloads/[[addon_'
                               'name]]\n\thttps://www.tukui.org/addons.php?id=[[addon_id]]\n\thttps://www.tukui.org/cla'
                               'ssic-addons.php?id=[[addon_id]]', highlight=False)

    def c_update(self, args, addline=False, update=True, force=False):
        if len(self.core.cfCache) > 0 or len(self.core.wowiCache) > 0:
            self.core.cfCache = {}
            self.core.wowiCache = {}
            self.core.checksumCache = {}
        if args:
            addons = [addon.strip() for addon in list(reader([args], skipinitialspace=True))[0]]
        else:
            addons = sorted(self.core.config['Addons'], key=lambda k: k['Name'].lower())
        exceptions = []
        with Progress('{task.completed:.0f}/{task.total}', '|', BarColumn(bar_width=None), '|',
                      auto_refresh=False, console=None if self.headless else self.console) as progress:
            task = progress.add_task('', total=len(addons))
            if not args:
                self.core.bulk_check(addons)
                self.core.bulk_check_checksum(addons, progress)
            while not progress.finished:
                for addon in addons:
                    try:
                        name, versionnew, versionold, modified = self.core.\
                            update_addon(addon if isinstance(addon, str) else addon['URL'], update, force)
                        if versionold:
                            if versionold == versionnew:
                                if modified:
                                    self.table.add_row('[bold red]Modified[/bold red]', name, versionold)
                                else:
                                    self.table.add_row('[green]Up-to-date[/green]', name, versionold)
                            else:
                                if modified:
                                    self.table.add_row('[bold red]Update suppressed[/bold red]', name, versionold)
                                else:
                                    self.table.add_row(f'[yellow]{"Updated " if update else "Update available"}'
                                                       f'[/yellow]', name, f'[yellow]{versionnew}[/yellow]')
                        else:
                            self.table.add_row(f'[bold black]Not installed[/bold black]', addon, '')
                    except Exception as e:
                        exceptions.append(e)
                    progress.update(task, advance=1 if args else 0.5, refresh=True)
        if addline:
            self.console.print('\n')
        self.console.print(self.table)
        if len(addons) == 0:
            self.console.print('Apparently there are no addons installed by CurseBreaker.\n'
                               'Command [green]import[/green] might be used to detect already installed addons.')
        if len(exceptions) > 0:
            self.handle_exception(exceptions, False)

    def c_force_update(self, args):
        if args:
            self.c_update(args, False, True, True)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a comma-separated list of addon names or '
                               'full links as an argument.')

    def c_status(self, args):
        self.c_update(args, False, False)

    def c_orphans(self, _):
        orphansd, orphansf = self.core.find_orphans()
        self.console.print('[green]Directories that are not part of any installed addon:[/green]')
        for orphan in sorted(orphansd):
            self.console.print(orphan.replace('[GIT]', '[yellow][[GIT]][/yellow]'), highlight=False)
        self.console.print('\n[green]Files that are leftovers after no longer installed addons:[/green]')
        for orphan in sorted(orphansf):
            self.console.print(orphan, highlight=False)

    def c_uri_integration(self, _):
        if self.os == 'Windows':
            self.core.create_reg()
            self.console.print('CurseBreaker.reg file was created. Attempting to import...')
            out = os.system('"' + str(Path(os.path.dirname(sys.executable), 'CurseBreaker.reg')) + '"')
            if out != 0:
                self.console.print('Import failed. Please try to import REG file manually.')
            else:
                os.remove('CurseBreaker.reg')
        else:
            self.console.print('This feature is available only on Windows.')

    def c_toggle_dev(self, args):
        if args:
            status = self.core.dev_toggle(args)
            if status is None:
                self.console.print('[bold red]This addon doesn\'t exist or it is not installed yet.[/bold red]')
            elif status == 0:
                self.console.print('Addon switched to the [yellow]beta[/yellow] channel.')
            elif status == 1:
                self.console.print('Addon switched to the [red]alpha[/red] channel.')
            elif status == 2:
                self.console.print('Addon switched to the [green]stable[/green] channel.')
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts an addon name as an argument.')

    def c_toggle_backup(self, _):
        status = self.core.backup_toggle()
        self.console.print('Backup of WTF directory is now:',
                           '[green]ENABLED[/green]' if status else '[red]DISABLED[/red]')

    def c_toggle_wa(self, args):
        if args:
            if args == self.core.config['WAUsername']:
                self.console.print(f'WeakAuras version check is now: [green]ENABLED[/green]\nAuras created by '
                                   f'[bold white]{self.core.config["WAUsername"]}[/bold white] are now included.')
                self.core.config['WAUsername'] = ''
            else:
                self.core.config['WAUsername'] = args.strip()
                self.console.print(f'WeakAuras version check is now: [green]ENABLED[/green]\nAuras created by '
                                   f'[bold white]{self.core.config["WAUsername"]}[/bold white] are now ignored.')
        else:
            if self.core.config['WAUsername'] == 'DISABLED':
                self.core.config['WAUsername'] = ''
                self.console.print('WeakAuras version check is now: [green]ENABLED[/green]')
            else:
                self.core.config['WAUsername'] = '******'
                shutil.rmtree(Path('Interface/AddOns/WeakAurasCompanion'), ignore_errors=True)
                self.console.print('WeakAuras version check is now: [red]DISABLED[/red]')
        self.core.save_config()

    def c_set_wa_api(self, args):
        if args:
            self.console.print('Wago API key is now set.')
            self.core.config['WAAPIKey'] = args.strip()
            self.core.save_config()
        elif self.core.config['WAAPIKey'] != '':
            self.console.print('Wago API key is now removed.')
            self.core.config['WAAPIKey'] = ''
            self.core.save_config()
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts API key as an argument.')

    def c_set_wa_wow_account(self, args):
        if args:
            args = args.strip()
            if os.path.isfile(Path(f'WTF/Account/{args}/SavedVariables/WeakAuras.lua')):
                self.console.print(f'WoW account name set to: [bold white]{args}[/bold white]')
                self.core.config['WAAccountName'] = args
                self.core.save_config()
            else:
                self.console.print('Incorrect WoW account name.')
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts the WoW account name as an argument.')

    def c_wa_update(self, _, verbose=True):
        if os.path.isdir(Path('Interface/AddOns/WeakAuras')):
            accounts = self.core.detect_accounts()
            if len(accounts) == 0:
                return
            elif len(accounts) > 1 and self.core.config['WAAccountName'] == '':
                if verbose:
                    self.console.print('More than one WoW account detected.\nPlease use [bold white]set_wa_wow_account['
                                       '/white] command to set the correct account name.')
                else:
                    self.console.print('\n[green]More than one WoW account detected.[/green]\nPlease use [bold white]se'
                                       't_wa_wow_account[/bold white] command to set the correct account name.')
                return
            elif len(accounts) == 1 and self.core.config['WAAccountName'] == '':
                self.core.config['WAAccountName'] = accounts[0]
                self.core.save_config()
            wa = WagoUpdater(self.core.config['WAUsername'], self.core.config['WAAccountName'],
                             self.core.config['WAAPIKey'])
            if self.core.waCompanionVersion != self.core.config['WACompanionVersion']:
                self.core.config['WACompanionVersion'] = self.core.waCompanionVersion
                self.core.save_config()
                force = True
            else:
                force = False
            wa.parse_storage()
            status = wa.check_updates()
            wa.install_companion(self.core.clientType, force)
            wa.install_data()
            if verbose:
                self.console.print('[green]Outdated WeakAuras:[/green]')
                for aura in status[0]:
                    self.console.print(aura, highlight=False)
                self.console.print('\n[green]Detected WeakAuras:[/green]')
                for aura in status[1]:
                    self.console.print(aura, highlight=False)
            else:
                self.console.print(f'\n[green]The number of outdated WeakAuras:[/green] {len(status[0])}',
                                   highlight=False)
        elif verbose:
            self.console.print('WeakAuras addon is not installed.')

    def c_search(self, args):
        if args:
            results = self.core.search(args)
            self.console.print('[green]Top results of your search:[/green]')
            for url in results:
                if self.core.check_if_installed(url):
                    self.console.print(f'{url} [yellow][[Installed]][/yellow]', highlight=False)
                else:
                    self.console.print(url, highlight=False)
        else:
            self.console.print('[green]Usage:[/green]\n\tThis command accepts a search query as an argument.')

    def c_import(self, args):
        hit, partial_hit, miss = self.core.detect_addons()
        if args == 'install' and len(hit) > 0:
            self.c_install(','.join(hit))
        else:
            self.console.print(f'[green]Addons found:[/green]')
            for addon in hit:
                self.console.print(addon)
            self.console.print(f'\n[yellow]Possible matches:[/yellow]')
            for addon in partial_hit:
                self.console.print(' [bold white]or[/bold white] '.join(addon))
            self.console.print(f'\n[red]Unknown directories:[/red]')
            for addon in miss:
                self.console.print(f'{addon}')
            self.console.print(f'\nExecute [bold white]import install[/bold white] command to install all detected addo'
                               f'ns.\nPossible matches need to be installed manually with the [bold white]install[/bold'
                               f' white] command.')

    def c_export(self, _):
        self.console.print(self.core.export_addons(), highlight=False)

    def c_help(self, _):
        self.console.print('[green]install [URL][/green]\n\tCommand accepts a comma-separated list of links.\n'
                           '[green]uninstall [URL/Name][/green]\n\tCommand accepts a comma-separated list of addon name'
                           's or full links.\n'
                           '[green]update [URL/Name][/green]\n\tCommand accepts a comma-separated list of addon names o'
                           'r full links.\n\tIf no argument is provided all non-modified addons will be updated.\n'
                           '[green]force_update [URL/Name][/green]\n\tCommand accepts a comma-separated list of addon n'
                           'ames or full links.\n\tSelected addons will be reinstalled or updated regardless of their c'
                           'urrent state.\n'
                           '[green]wa_update[/green]\n\tCommand detects all installed WeakAuras and generate WeakAura'
                           's Companion payload.\n'
                           '[green]status[/green]\n\tPrints the current state of all installed addons.\n'
                           '[green]orphans[/green]\n\tPrints list of orphaned directories and files.\n'
                           '[green]search [Keyword][/green]\n\tExecutes addon search on CurseForge.\n'
                           '[green]import[/green]\n\tCommand attempts to import already installed addons.\n'
                           '[green]export[/green]\n\tCommand prints list of all installed addons in a form suitable f'
                           'or sharing.\n'
                           '[green]toggle_backup[/green]\n\tEnables/disables automatic daily backup of WTF directory.'
                           '\n[green]toggle_dev [Name][/green]\n\tCommand accepts an addon name as argument.\n\tPrior'
                           'itizes alpha/beta versions for the provided addon.\n'
                           '[green]toggle_wa [Username][/green]\n\tEnables/disables automatic WeakAuras updates.\n\tI'
                           'f a username is provided check will start to ignore the specified author.\n'
                           '[green]set_wa_api [API key][/green]\n\tSets Wago API key required to access private auras'
                           '.\n\tIt can be procured here: [link=https://wago.io/account]https://wago.io/account[/link]'
                           '\n[green]set_wa_wow_account [Account name][/green]\n\tSets WoW account used by WeakAuras up'
                           'dater.\n\tNeeded only if WeakAuras are used on more than one WoW account.\n'
                           '[green]uri_integration[/green]\n\tEnables integration with CurseForge page.\n\t[i]"Install"'
                           '[/i] button will now start this application.\n'
                           '\n[bold green]Supported URL:[/bold green]\n\thttps://www.curseforge.com/wow/addons/[[addon_'
                           'name]] [bold white]|[/bold white] cf:[[addon_name]]\n\thttps://www.wowinterface.com/downloa'
                           'ds/[[addon_name]] [bold white]|[/bold white] wowi:[[addon_id]]\n\thttps://www.tukui.org/add'
                           'ons.php?id=[[addon_id]] [bold white]|[/bold white] tu:[[addon_id]]\n\thttps://www.tukui.org'
                           '/classic-addons.php?id=[[addon_id]] [bold white]|[/bold white] tuc:[[addon_id]]\n\tElvUI [b'
                           'old white]|[/bold white] ElvUI:Dev\n\tTukui\n\tSLE:Dev', highlight=False)

    def c_exit(self, _):
        sys.exit(0)
)

# actually, create a custom completion is good.

class MyCustomCompleter(Completer):

    def get_completions(self, document, complete_event):
        length = len(document.text)
        yield Completion('completion1', start_position=-length,
                        style='bg:ansiyellow fg:ansiblack')

        yield Completion('completion2', start_position=-length,
                        style='bg:ansiyellow fg:ansiwhite')


if __name__ == "__main__":
    session = PromptSession(history=FileHistory('~/.myhistory'))
    while True:
        try:

            content = session.prompt(">", completer=MyCustomCompleter(), complete_while_typing=True)
        except KeyboardInterrupt:
            continue
        except EOFError:
            break
        else:
            print(f"You entered: {content}")

    print("exit..")