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)
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)
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!')
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)
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]}
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()
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)
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
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)
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)
('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)
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!')
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')
#!/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}'")
def __init__(self): self.session = PromptSession() self.config_mode = False self.prompt = 'brewer@localhost> ' self.config_prompt = 'brewer@localhost# '
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())
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()
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
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!')
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()
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()
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...")
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
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
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
def __init__(self, history: History = None): self._last_exception = None self._session = PromptSession(history=history) self.prompt = '> ' self.prompt_style = Style.from_dict({'': 'bold'})
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")
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
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))
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
"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")
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
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)
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
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..")