def install_packages(packages): """ Install a package using system package manager This method is currently using os.system instead of subprocess.run or subprocess.Popen because subprocess doesn't seem to handle some of the TUIs well. """ Avalon.warning( 'If the installation is unsuccessful, you should consider updating the package manager cache', log=False) # Convert packages list into a string if len(packages) > 1: packages_string = ' '.join(packages) else: packages_string = packages[0] if shutil.which('apt-get'): return os.system(f'apt-get install {packages_string} -y') elif shutil.which('yum'): return os.system(f'yum install {packages_string} -y') elif shutil.which('pacman'): return os.system(f'pacman -S {packages_string} --noconfirm') else: Avalon.error( 'Sorry, we can\'t find a package manager that we currently support. Aborting..' ) Avalon.error('Currently Supported: apt, yum, pacman') return False
def _setup_ufw(self): """ Enable UFW to controll the firewall """ print(Avalon.FM.BD + '\nEnable UFW firewall?' + Avalon.FM.RST) print('Do you want SCUTUM to help configuring and enabling UFW firewall?') print('This may help preventing a lot of scanning and attacks') if Avalon.ask('Enable?', True): # If ufw is not installed if shutil.which('ufw') is None: if Avalon.ask('UFW is not installed. Install?', True): Utilities.install_packages(['ufw']) else: Avalon.warning('UFW package not available, disabling UFW') self.config['Ufw']['handled'] = False return ufwctrl = Ufw() print('SCUTUM can configure UFW Firewall for you') print('However this will reset your current UFW configurations') print('It is recommended to do so the first time you install SCUTUM') if Avalon.ask('Let SCUTUM configure UFW for you?', True): ufwctrl.initialize(True) else: Avalon.info('Okay. Then we will simply enable it for you') ufwctrl.enable() print('If you let SCUTUM handle UFW, then UFW will be activated and deactivated with SCUTUM') if Avalon.ask('Let SCUTUM handle UFW?', True): self.config['Ufw']['handled'] = True else: self.config['Ufw']['handled'] = False else: self.config['Ufw']['handled'] = False Avalon.info('You can turn it on whenever you change your mind')
def install_wicd_scripts(self): """ Write scutum scripts for WICD """ print(Avalon.FG.G + '[+] INFO: Installing for WICD' + Avalon.FM.RST + '.....', end='') if not os.path.isdir('/etc/wicd/'): print(Avalon.FG.R + Avalon.FM.BD + 'ERROR' + Avalon.FM.RST) Avalon.warning('WICD folder not found! WICD does not appear to be installed!') if Avalon.ask('Continue anyway? (Create Directories)', False): Utilities.execute(['mkdir', '-p', '/etc/wicd/scripts/postconnect/']) Utilities.execute(['mkdir', '-p', '/etc/wicd/scripts/postdisconnect/']) else: Avalon.warning('Aborting installation for WICD') return False with open('/etc/wicd/scripts/postconnect/scutum_connect', 'w') as postconnect: postconnect.write('#!/bin/bash\n') postconnect.write('scutum') postconnect.close() with open('/etc/wicd/scripts/postdisconnect/scutum_disconnect', 'w') as postdisconnect: postdisconnect.write('#!/bin/bash\n') postdisconnect.write('scutum --reset') postdisconnect.close() Utilities.execute(['chown', 'root:', '/etc/wicd/scripts/postconnect/scutum_connect']) Utilities.execute(['chmod', '755', '/etc/wicd/scripts/postconnect/scutum_connect']) Utilities.execute(['chown', 'root:', '/etc/wicd/scripts/postdisconnect/scutum_disconnect']) Utilities.execute(['chmod', '755', '/etc/wicd/scripts/postdisconnect/scutum_disconnect']) print(Avalon.FG.G + Avalon.FM.BD + 'SUCCEED' + Avalon.FM.RST) return True
def run(self): global successes self.running = True while self.running and (self.limit is None or successes < self.limit): self.send_request() time.sleep(self.interval) Avalon.warning(f"Thread {self.name} exiting")
def read_config(): """ Parses configuration This function parses the configuration file and load the configurations into the program TODO: Do something about KeyError """ if not os.path.isfile(args.config): # Configuration not found Avalon.error('SCUTUM configuration file not found! Please re-install SCUTUM!') Avalon.warning('Please run \"scutum --install\" before using it for the first time') raise FileNotFoundError(args.config) # Initialize python confparser and read config with open(args.config, 'r') as raw_config: config = json.load(raw_config) # Get controlled interfaces interfaces = [] for interface in config['Interfaces']['interfaces']: if os.path.isdir(f'/sys/class/net/{interface}'): # Check if interface is connected interfaces.append(interface) # Get controlled network controllers network_controllers = config['NetworkControllers']['controllers'] # Check if we should handle ufw ufw_handled = config['Ufw']['handled'] # Get ARP Controller driver arp_driver = config['ArpController']['driver'] return interfaces, network_controllers, ufw_handled, arp_driver
def __init__(self, driver='nftables'): self.driver = driver if self.driver != 'nftables' and self.driver != 'arptables': Avalon.warning('Unrecognized ARP controller driver {}'.format( self.driver)) Avalon.warning('Falling back to nftables') self.driver = 'nftables'
def main(): """ AnyRadius Manager main function This function can only be executed when this file is not being imported. """ # Create database controller connection try: if sys.argv[1].lower() == 'help': print_help() exit(0) elif sys.argv[1].lower() == 'config': config_path = sys.argv[2] else: config_path = '/etc/anyradius.json' except IndexError: Avalon.error('Error parsing configuration file path') exit(1) Avalon.debug_info('Reading config from: {}'.format(config_path)) db_host, db_user, db_pass, db, table = read_config(config_path) Avalon.info('Connecting to RADIUS database') rdb = UserDatabase(db_host, db_user, db_pass, db, table) Avalon.info('Database connection established') # Begin command interpreting try: if sys.argv[1].lower() == 'interactive' or sys.argv[1].lower( ) == 'int': print_legal_info() # Set command completer completer = ShellCompleter(COMMANDS) readline.set_completer(completer.complete) readline.parse_and_bind('tab: complete') # Launch interactive trojan shell prompt = '{}[AnyRadius]> {}'.format(Avalon.FM.BD, Avalon.FM.RST) while True: command_interpreter(rdb, [''] + input(prompt).split(' ')) else: # Return to shell with command return value exit(command_interpreter(rdb, sys.argv[0:])) except IndexError: Avalon.warning('No commands specified') exit(0) except (MySQLdb.Error, MySQLdb.Warning): Avalon.error('Database error') traceback.print_exc() exit(1) except (KeyboardInterrupt, EOFError): Avalon.warning('Exiting') exit(0) except Exception: Avalon.error('Exception caught') traceback.print_exc() exit(1)
def command_interpreter(commands): """ WGC shell command interpreter This function interprets commands from CLI or the interactive shell, and passes the parameters to the corresponding functions. """ try: # Try to guess what the user is saying possibilities = [ s for s in COMMANDS if s.lower().startswith(commands[1]) ] if len(possibilities) == 1: commands[1] = possibilities[0] if commands[1].replace(' ', '') == '': result = 0 elif commands[1].lower() == 'help': print_help() result = 0 elif commands[1].lower() == 'showpeers': for peer in pm.peers: print_peer_config(peer) result = 0 elif commands[1].lower() == 'jsonloadprofile': result = pm.json_load_profile(commands[2]) elif commands[1].lower() == 'jsonsaveprofile': result = pm.json_save_profile(commands[2]) elif commands[1].lower() == 'pickleloadprofile': result = pm.pickle_load_profile(commands[2]) elif commands[1].lower() == 'picklesaveprofile': result = pm.pickle_save_profile(commands[2]) elif commands[1].lower() == 'newprofile': result = pm.new_profile() elif commands[1].lower() == 'addpeer': result = add_peer() elif commands[1].lower() == 'deletepeer': result = delete_peer(commands[2]) elif commands[1].lower() == 'generateconfigs': result = generate_configs(commands[2]) elif commands[1].lower() == 'exit' or commands[1].lower() == 'quit': Avalon.warning('Exiting') exit(0) elif len(possibilities) > 0: Avalon.warning(f'Ambiguous command \"{commands[1]}\"') print('Use \"Help\" command to list available commands') result = 1 else: Avalon.error('Invalid command') print('Use \"Help\" command to list available commands') result = 1 return result except IndexError: Avalon.error('Invalid arguments') print('Use \"Help\" command to list available commands') result = 0
def new_profile(self): """ Create new profile and flush the peers list """ # Warn the user before flushing configurations Avalon.warning('This will flush the currently loaded profile!') if len(self.peers) != 0: if not Avalon.ask('Continue?', False): return # Reset self.peers and start enrolling new peer data self.peers = []
def upgrade_full(self): """ upgrade all packages This method checks if there are packages available for updating and update the packages if updating them won't remove any packages from the system. Often times when a bad source is added to the system, APT tends to remove a number of packages from the system when upgrading which is very risky. """ Avalon.info("Starting automatic upgrade") Avalon.info("Updating APT cache") with open("/etc/apt/sources.list", "r") as aptlist: for line in aptlist: if ("ubuntu.com" in line and distro.linux_distribution()[0] != "Ubuntu" and line.replace(" ", "")[0] != "#"): Avalon.warning("Ubuntu source detected in source.list!") Avalon.warning( "Continue upgrading might cause severe consequences!") if Avalon.ask("Are you sure that you want to continue?", False): break else: Avalon.warning("Aborting system upgrade..") sys.exit(0) self.update() Avalon.info("APT cache updated") if len(self.import_list) != 0: Avalon.ask( f"Detected un-imported keys: {' '.join(self.import_list)}") # if there are no upgrades available Avalon.info("Checking package updates") if self.no_upgrades(): Avalon.debug_info("No upgrades available") # if upgrades are available else: Avalon.info("Checking if full upgrade is safe") # if upgrade is safe, use -y flag on apt-get full-upgrade # otherwise, let user confirm the upgrade if self.full_upgrade_safe(): Avalon.debug_info("Full upgrade is safe") Avalon.info("Starting APT full upgrade") self.full_upgrade() else: Avalon.warning("Full upgrade is NOT safe") Avalon.warning("Requiring human confirmation") self.manual_full_upgrade()
def _wait(self): """wait for subprocesses in process pool to complete""" Avalon.debug_info(_("Main process waiting for subprocesses to exit")) try: # while process pool not empty while self.process_pool: # if stop signal received, terminate all processes if self.running is False: raise SystemExit for process in self.process_pool: process_status = process.poll() # if process finished if process_status is None: continue # if return code is not 0 elif process_status != 0: Avalon.error( _("Subprocess {} exited with code {}").format( process.pid, process_status ) ) raise subprocess.CalledProcessError( process_status, process.args ) else: Avalon.debug_info( _("Subprocess {} exited with code {}").format( process.pid, process_status ) ) self.process_pool.remove(process) time.sleep(0.1) except (KeyboardInterrupt, SystemExit) as e: Avalon.warning(_("Stop signal received")) self._terminate_subprocesses() raise e except (Exception, subprocess.CalledProcessError) as e: Avalon.error(_("Subprocess execution ran into an error")) self._terminate_subprocesses() raise e
def _install_arp_controller_driver(self): """ Install the CLI tool if not installed """ if self.config['ArpController']['driver'] == 'nftables': binary = 'nft' elif self.config['ArpController']['driver'] == 'arptables': binary = 'arptables' if shutil.which(binary) is None: Avalon.warning('ARP controller driver is not installed') if Avalon.ask(f'Install {self.config["ArpController"]["driver"]}?', True): Utilities.install_packages([self.config['ArpController']['driver']]) else: Avalon.error('ARP controller driver not installed') Avalon.error('SCUTUM relies on the driver to run') Avalon.error('Aborting installation') exit(1)
def command_interpreter(commands): """ WGC shell command interpreter This function interprets commands from CLI or the interactive shell, and passes the parameters to the corresponding functions. """ try: # Try to guess what the user is saying possibilities = [s for s in COMMANDS if s.lower().startswith(commands[1])] if len(possibilities) == 1: commands[1] = possibilities[0] if commands[1].replace(' ', '') == '': result = 0 elif commands[1].lower() == 'help': print_help() result = 0 elif commands[1].lower() == 'gencacert': cacert = CACert(commands[2]) cacert.generate() result = 0 elif commands[1].lower() == 'genusercert': usercert = UserCert(commands[2], commands[3], commands[4]) usercert.generate() result = 0 elif commands[1].lower() == 'genservercert': servercert = ServerCert(commands[2], commands[3], commands[4], commands[5]) servercert.generate() result = 0 elif commands[1].lower() == 'exit' or commands[1].lower() == 'quit': Avalon.warning('Exiting') exit(0) elif len(possibilities) > 0: Avalon.warning('Ambiguous command \"{}\"'.format(commands[1])) print('Use \"Help\" command to list available commands') result = 1 else: Avalon.error('Invalid command') print('Use \"Help\" command to list available commands') result = 1 return result except IndexError: Avalon.error('Invalid arguments') print('Use \"Help\" command to list available commands') result = 0
def xinstall(packages: list): """ install only packages that are not installed By using the xinstall function to install packages, already-installed packages will not get marked as manually installed by APT. Arguments: packages {list} -- list of packages to install """ not_installed = [] installed = [] # get a list of all locally installed packages apt_list = subprocess.run( ['apt', 'list'], stderr=subprocess.DEVNULL).stdout.decode().split('\n') for line in apt_list: for package in packages: if package == line.split('/')[0] and 'installed' not in line: not_installed.append(package) elif package == line.split('/')[0] and 'installed' in line: installed.append(package) Avalon.info('Packages already installed:') print(' '.join(installed)) Avalon.info('Packages to be installed:') print(' '.join(not_installed)) execute = ['apt-get', 'install', '-s'] execute.extend(not_installed) Avalon.info('Launching a dry-run') subprocess.call(execute) if Avalon.ask('Confirm installation:', False): # swap -s flag with -y for actual installation execute[execute.index('-s')] = '-y' subprocess.call(execute) else: Avalon.warning('Installation aborted')
def create_char_pool(args): """Create a pool of characters This function creates a pool of characters which the random password generator will choose characters from. Arguments: args {argparse.Namespace} -- parsed arguments Returns: string -- string of characters """ symbols = ''.join([chr(i) for i in range(33, 48)]) char_pool = "" if args.uppercase: if not args.quiet: Avalon.debug_info("Including Uppercase characters") char_pool += ascii_uppercase if args.lowercase: if not args.quiet: Avalon.debug_info("Including lowercase characters") char_pool += ascii_lowercase if args.digits: if not args.quiet: Avalon.debug_info("Including digits") char_pool += digits if args.symbols: if not args.quiet: Avalon.debug_info("Including symbols") char_pool += symbols if args.all or not (args.uppercase or args.lowercase or args.digits or args.symbols): if not args.quiet: Avalon.debug_info("Including all characters") if args.uppercase or args.lowercase or args.digits or args.symbols: if not args.quiet: Avalon.warning( "Ignoring other switches since including all characters") char_pool = ascii_letters + digits + symbols return char_pool
def _get_controlled_nm(self): """ Ask which network controller to hook to """ while True: print(Avalon.FM.BD + '\nWhich network controller do you want to install for?' + Avalon.FM.RST) print('1. WICD') print('2. Network-Manager') print('3. Both') selection = Avalon.gets('Please select: (index number): ') if selection == '1': if self.install_wicd_scripts() is not True: Avalon.error('SCUTUM Script for WICD has failed to install!') Avalon.error('Aborting Installation...') exit(1) self.config['NetworkControllers']['controllers'] = 'wicd' break elif selection == '2': if self.install_nm_scripts(self.config['Interfaces']['interfaces']) is not True: Avalon.error('SCUTUM Script for NetworkManager has failed to install!') Avalon.error('Aborting Installation...') exit(1) self.config['NetworkControllers']['controllers'] = 'NetworkManager' break elif selection == '3': ifaces = ['wicd', 'NetworkManager'] if self.install_wicd_scripts() is not True: Avalon.warning('Deselected WICD from installation') ifaces.remove('wicd') if self.install_nm_scripts(self.config['Interfaces']['interfaces']) is not True: Avalon.warning('Deselected NetworkManager from installation') ifaces.remove('NetworkManager') if len(ifaces) == 0: Avalon.error('All SCUTUM Scripts have failed to install!') Avalon.error('Aborting Installation...') exit(1) self.config['NetworkControllers']['controllers'] = ifaces break else: Avalon.error('Invalid Input!')
def no_upgrades() -> bool: """ check if no upgrades are available Determine if there are no upgrades available Returns: bool -- True if there are packages available """ output = subprocess.run( ['apt-get', 'full-upgrade', '-s'], stdout=subprocess.PIPE).stdout.decode().split('\n') for line in output: parsed_line = line.replace('and', ',').replace(' ', '').split(',') if parsed_line[0] == '0upgraded' and parsed_line[ 1] == '0newlyinstalled': if parsed_line[3] != '0notupgraded.': Avalon.warning('Some packages are not upgraded') Avalon.warning('Attempting to print messages from APT:') subprocess.call(['apt', 'upgrade', '-s']) return True return False
def no_upgrades() -> bool: """ check if no upgrades are available Determine if there are no upgrades available Returns: bool -- True if there are packages available """ output = (subprocess.run( ["/usr/bin/apt-get", "full-upgrade", "-s"], stdout=subprocess.PIPE).stdout.decode().split("\n")) for line in output: parsed_line = line.replace("and", ",").replace(" ", "").split(",") if parsed_line[0] == "0upgraded" and parsed_line[ 1] == "0newlyinstalled": if parsed_line[3] != "0notupgraded.": Avalon.warning("Some packages are not upgraded") Avalon.warning("Attempting to print messages from APT:") subprocess.call(["/usr/bin/apt", "upgrade", "-s"]) return True return False
def json_save_profile(self, profile_path): """ Save current profile to a JSON file """ # If profile already exists (file or link), ask the user if # we should overwrite it. if os.path.isfile(profile_path) or os.path.islink(profile_path): if not Avalon.ask('File already exists. Overwrite?', True): Avalon.warning('Aborted saving profile') return 1 # Abort if profile_path points to a directory if os.path.isdir(profile_path): Avalon.warning('Destination path is a directory') Avalon.warning('Aborted saving profile') return 1 # Finally, write the profile into the destination file Avalon.debug_info(f'Writing profile to: {profile_path}') peers_dict = {} peers_dict['peers'] = [] for peer in pm.peers: peers_dict['peers'].append(peer.__dict__) with open(profile_path, 'w') as profile: json.dump(peers_dict, profile, indent=4) profile.close()
def save_profile(self, profile_path): """ Save current profile to a file Serializes the current profile with pickle and dumps it into a file. """ # If profile already exists (file or link), ask the user if # we should overwrite it. if os.path.isfile(profile_path) or os.path.islink(profile_path): if not Avalon.ask('File already exists. Overwrite?', True): Avalon.warning('Aborted saving profile') return 1 # Abort if profile_path points to a directory if os.path.isdir(profile_path): Avalon.warning('Destination path is a directory') Avalon.warning('Aborted saving profile') return 1 # Finally, write the profile into the destination file Avalon.debug_info('Writing profile to: {}'.format(profile_path)) with open(profile_path, 'wb') as profile: pickle.dump(pm.peers, profile) profile.close()
def main(): """ WireGuard Mesh Configurator main function This function controls the main flow of this program. """ try: if sys.argv[1].lower() == 'help': print_help() exit(0) except IndexError: pass # Begin command interpreting try: if sys.argv[1].lower() == 'interactive' or sys.argv[1].lower( ) == 'int': print_welcome() # Set command completer completer = ShellCompleter(COMMANDS) readline.set_completer(completer.complete) readline.parse_and_bind('tab: complete') # Launch interactive trojan shell prompt = '{}[WGC]> {}'.format(Avalon.FM.BD, Avalon.FM.RST) while True: command_interpreter([''] + input(prompt).split(' ')) else: # Return to shell with command return value exit(command_interpreter(sys.argv[0:])) except IndexError: Avalon.warning('No commands specified') print_help() exit(0) except (KeyboardInterrupt, EOFError): Avalon.warning('Exiting') exit(0) except Exception: Avalon.error('Exception caught') traceback.print_exc() exit(1)
def upgrade_kpm(): """ upgrade KPM Upgrades KPM by downloading the latest version from GitHub. Replaces the current file being executed. """ try: # get python script web page kpm_request = requests.get(GITHUB_KPM_FILE) if kpm_request.status_code != requests.codes.ok: kpm_request.raise_for_status() # write web page content to file with open(os.path.abspath(__file__), 'wb') as kpm_file: kpm_file.write(kpm_request.content) Avalon.info('KPM has been updated successfully') Avalon.info('Please relaunch KPM') except Exception: Avalon.error('There was an error updating KPM') Avalon.warning('You might have to reinstall KPM manually')
def install_nm_scripts(self, interfaces): """ Write scutum scripts for Network Manager """ print(Avalon.FG.G + '[+] INFO: Installing for NetworkManager' + Avalon.FM.RST + '.....', end='') if not os.path.isdir('/etc/NetworkManager/dispatcher.d/'): print(Avalon.FG.R + Avalon.FM.BD + 'ERROR' + Avalon.FM.RST) Avalon.warning('NetworkManager folders not found! NetworkManager does not appear to be installed!') if Avalon.ask('Continue anyway? (Create Directories)', False): Utilities.execute(['mkdir', '-p', '/etc/NetworkManager/dispatcher.d/']) else: Avalon.warning('Aborting installation for NetworkManager') return False with open('/etc/NetworkManager/dispatcher.d/scutum', 'w') as nmScript: nmScript.write('#!/usr/bin/env python3\n') nmScript.write('\n') nmScript.write('import sys\n') nmScript.write('import os\n') nmScript.write('\n') nmScript.write('try:\n') nmScript.write(' interface = sys.argv[1]\n') nmScript.write(' status = sys.argv[2]\n') nmScript.write('except IndexError:\n') nmScript.write(' exit(0)\n') nmScript.write('\n') nmScript.write('if status == \"down\":\n') nmScript.write(' os.system(\"scutum --reset\")\n') nmScript.write(' exit(0)\n') nmScript.write('\n') nmScript.write('if status == \"up\":\n') nmScript.write(' os.system(\"scutum\")\n') nmScript.write(' exit(0)\n') nmScript.close() Utilities.execute(['chown', 'root:', '/etc/NetworkManager/dispatcher.d/scutum']) Utilities.execute(['chmod', '755', '/etc/NetworkManager/dispatcher.d/scutum']) print(Avalon.FG.G + Avalon.FM.BD + 'SUCCEED' + Avalon.FM.RST) return True
def _install_defense_matrix(self): """ Installs defense matrix to system and link defense matrix executable to bin path. """ # Get installation destination from user user_install_dir = Avalon.gets( 'Installation destination (\"/usr/share/defense-matrix\")') if user_install_dir != '': self.install_dir = user_install_dir # If files already at the correct directory, pass if self.current_dir == self.install_dir: pass # Check if destination directory occupied else: if os.path.isdir(self.install_dir) or os.path.islink( self.install_dir): if not Avalon.ask('Target directory exists. Overwrite?', True): Avalon.warning( 'Aborting installation: target directory not writable') if os.path.isdir(self.install_dir): shutil.rmtree(self.install_dir) else: os.remove(self.install_dir) # Copy defense matrix to destination directory shutil.copytree(self.current_dir, self.install_dir) # If defense-matrix is already linked to path, remove it if os.path.islink(self.executable) or os.path.isfile(self.executable): os.remove(self.executable) # Remove old file or symbolic links # Link current defense-matrix.py to path os.symlink('{}/bin/defense-matrix.py'.format(self.current_dir), self.executable)
def getPost(self: None, pageNumber: int, ajax: bool = True, useTemp: bool = True): # 获得html源文件函数 self.__workPageNumber = pageNumber link = self.__postLink + str(pageNumber) existTemp = self.__tempSave.getSameTemp() if existTemp.get('html') and useTemp: for i in existTemp['html']: if int(i[1]) == int(pageNumber): Avalon.debug_info('第%d页已经在临时文件中存在,跳过' % pageNumber) return self.__tempSave.readFileByID(i) if ajax is False: link = link.replace('ajax=1&', '') for tryTimes in range(1, 11): try: postRequest = request.Request(link) try: # 设置程序请求头,伪装爬虫(必要性存疑) postRequest.add_header('User-Agent', (random.choice( self.__userAgent)).replace('\n', '')) postRequest.add_header('Referer', 'https://tieba.baidu.com') except: continue else: postRead: bytes = request.urlopen(postRequest, timeout=5).read() if self.debug: Avalon.debug_info('链接:"%s"请求头:%s.' % (link, postRequest.headers)) # 错误处理 except error.URLError as e: Avalon.warning("获取帖子正文失败!原因:%s(%s/10)" % (str(e.reason), str(tryTimes))) except timeout as e: Avalon.warning("获取帖子正文失败!原因:%s(%s/10)" % (str(e), str(tryTimes))) except KeyboardInterrupt: Avalon.critical("用户强制退出") quit(1) except: Avalon.warning("获取帖子正文失败!原因:未知错误(%s/10)" % tryTimes) # 没有错误,结束循环 else: if self.debug: Avalon.debug_info('Link %s Get Successed.' % link) break else: Avalon.error('获取失败!') if self.debug: Avalon.debug('Link:%s' % link) quit(1) if useTemp is True: self.__tempSave.savePostRaw(postRead.decode(errors='ignore'), pageNumber=pageNumber) return (postRead.decode(errors='ignore'))
def upgrade_kpm(): """ upgrade KPM Upgrades KPM by downloading the latest version from GitHub. Replaces the current file being executed. """ try: latest_json = requests.get( "https://api.github.com/repos/k4yt3x/kpm/releases/latest").json() for asset in latest_json["assets"]: if asset["name"] == "kpm.py": latest_version_url = asset["browser_download_url"] break else: Avalon.warning("Unable to find the latest version's download URL") return # get python script web page kpm_request = requests.get(latest_version_url) if kpm_request.status_code != requests.codes.ok: kpm_request.raise_for_status() # write web page content to file with pathlib.Path(__file__).open(mode="wb") as kpm_file: kpm_file.write(kpm_request.content) Avalon.info("KPM has been updated successfully") Avalon.info("Please relaunch KPM") sys.exit(0) except Exception as e: Avalon.error("There was an error updating KPM") Avalon.warning("You might have to reinstall KPM manually") raise e
def check_version(): """ check if KPM is up-to-date Check if KPM is up to date with the the newest version on GitHub. Prompt the user to upgrade if the local version is not the newest. """ # get version number of KPM on GitHub Avalon.debug_info('Checking KPM Version') for line in requests.get(GITHUB_KPM_FILE).text.split('\n'): if 'VERSION = ' in line: server_version = line.split(' ')[-1].replace('\'', '') break Avalon.debug_info(f'Server version: {server_version}') # if the server version is newer than local version if server_version > VERSION: Avalon.info('Here\'s a newer version of KPM!') if Avalon.ask('Update to the newest version?', True): upgrade_kpm() else: Avalon.warning('Ignoring update') else: Avalon.debug_info('KPM is already on the newest version')
def command_interpreter(db_connection, commands): """ AnyRadius shell command interpreter """ try: # Try to guess what the user is saying possibilities = [ s for s in COMMANDS if s.lower().startswith(commands[1]) ] if len(possibilities) == 1: commands[1] = possibilities[0] if commands[1].replace(' ', '') == '': result = 0 elif commands[1].lower() == 'help': print_help() result = 0 elif commands[1].lower() == 'truncateusertable': Avalon.warning('By truncating you will LOSE ALL USER DATA') if Avalon.ask('Are you sure you want to truncate?'): result = db_connection.truncate_user_table() else: Avalon.warning('Operation canceled') result = 0 elif commands[1].lower() == 'adduser': result = db_connection.add_user(commands[2], commands[3]) elif commands[1].lower() == 'deluser': result = db_connection.del_user(commands[2]) elif commands[1].lower() == 'showusers': result = db_connection.show_users() elif commands[1].lower() == 'exit' or commands[1].lower() == 'quit': Avalon.warning('Exiting') exit(0) elif len(possibilities) > 0: Avalon.warning('Ambiguous command \"{}\"'.format(commands[1])) print('Use \"Help\" command to list available commands') result = 1 else: Avalon.error('Invalid command') print('Use \"Help\" command to list available commands') result = 1 return result except IndexError: Avalon.error('Invalid arguments') print('Use \"Help\" command to list available commands') result = 0
def uploadSingleImage(self: None, imageFilePath: str): form = MultiPartForm() with open(imageFilePath, 'rb') as f: form.add_file('image', f.name, f) # 文件提交 form.add_field('token', '') # 文件上传密钥,默认为空 # 默认选择新浪图床(推荐),还可以选择 SouGou:搜狗图床,Smms:https://sm.ms 图床 form.add_field('apiSelect', 'Sina') r = request.Request('https://image.mnixry.cn/api/v1/upload', data=bytes(form)) # 用生成好的表单参数制造请求 r.add_header('User-Agent', self.__getUserAgent()) # 随机UA(必要性存疑) # 提交表单类型(主要是Boundary) r.add_header('Content-type', form.get_content_type()) r.add_header('Content-length', len(bytes(form))) # 提交表单大小(单位:bytes) if self.__debugMode: Avalon.debug_info( '文件名:%s,请求头:%s' % (os.path.split(imageFilePath)[1], str(r.headers))) for i in range(1, 11): try: uploadRes = request.urlopen(r, timeout=10).read().decode() except error.URLError as e: if not (self.__ignoreTimeOut and ('timed out' in str(e.reason))): Avalon.warning('图片上传失败!原因:%s[%d/10]' % (e.reason, i)) except timeout as e: if not self.__ignoreTimeOut: Avalon.warning('图片上传失败!原因:%s[%d/10]' % (e, i)) except: Avalon.warning('图片上传失败!原因:未知错误[%d/10]' % i) else: uploadRes = json.loads(uploadRes) if int(uploadRes['code']) != 200: Avalon.warning('图片上传失败!原因:%s[%d/10]' % (uploadRes['msg'], i)) continue else: del form break else: return (False) if self.__debugMode: Avalon.debug_info('图片上传成功!图床链接:%s,本地地址:%s' % (uploadRes['data']['url'], imageFilePath)) return (uploadRes['data']['url'])
def check_version(): """ check if KPM is up-to-date Check if KPM is up to date with the the newest version on GitHub. Prompt the user to upgrade if the local version is not the newest. """ # get version number of KPM on GitHub Avalon.info("Checking KPM's Version") latest = requests.get( "https://api.github.com/repos/k4yt3x/kpm/releases/latest") latest_json = latest.json() # if rate limit is exceeded, 403 will be returned if (latest.status_code == requests.codes.forbidden and "API rate limit exceeded" in latest_json["message"]): Avalon.warning("GitHub API rate limit exceeded") return # if the status code isn't 200, warn the user and skip the rest of the checks elif latest.status_code != requests.codes.ok: Avalon.warning("GitHub API request encountered an error") return latest_version = latest_json["tag_name"] Avalon.debug_info(f"Server version: {latest_version}") # if the server version is newer than local version if version.parse(latest_version) > version.parse(VERSION): Avalon.info( f"There is a newer version of KPM available ({latest_version})") if Avalon.ask("Update to the newest version?", True): upgrade_kpm() else: Avalon.warning("Skipping the upgrade for now") else: Avalon.debug_info(f"KPM is already on the newest version ({VERSION})")