From c0553fc8cb4f3e2037b1f0cfc32cde7e67054bd5 Mon Sep 17 00:00:00 2001 From: George Pickering <9803299+bigpick@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:55:28 -0400 Subject: [PATCH] feat: rotating client.log --- __main__.py | 9 +++++---- changelog.md | 8 +++++++- htpclient/initialize.py | 6 +++--- tests/test_hashcat_brain.py | 12 +++++------ tests/test_hashcat_files.py | 12 +++++------ tests/test_hashcat_files_7z.py | 32 +++++++++++++++--------------- tests/test_hashcat_preprocessor.py | 24 +++++++++++----------- tests/test_hashcat_runtime.py | 8 ++++---- tests/test_hashcat_simple.py | 20 +++++++++---------- 9 files changed, 69 insertions(+), 62 deletions(-) diff --git a/__main__.py b/__main__.py index 83bfe3c..308bd5b 100644 --- a/__main__.py +++ b/__main__.py @@ -20,6 +20,7 @@ from htpclient.jsonRequest import * from htpclient.dicts import * import logging +from logging.handlers import RotatingFileHandler from htpclient.task import Task @@ -100,8 +101,8 @@ def init_logging(args): print_format = '%(message)s' date_format = '%Y-%m-%d %H:%M:%S' log_level = logging.INFO - logfile = open('client.log', "a", encoding="utf-8") - + file_handler = RotatingFileHandler('client.log', maxBytes=args.max_log_size, backupCount=args.max_log_backups) + file_handler.setFormatter(logging.Formatter(log_format)) logging.getLogger("requests").setLevel(logging.WARNING) CONFIG = Config() @@ -111,8 +112,6 @@ def init_logging(args): log_level = logging.DEBUG logging.getLogger("requests").setLevel(logging.DEBUG) logging.basicConfig(level=log_level, format=print_format, datefmt=date_format) - file_handler = logging.StreamHandler(logfile) - file_handler.setFormatter(logging.Formatter(log_format)) logging.getLogger().addHandler(file_handler) @@ -334,6 +333,8 @@ def de_register(): parser.add_argument('--preprocessors-path', type=str, required=False, help='Use given folder path as preprocessors location') parser.add_argument('--zaps-path', type=str, required=False, help='Use given folder path as zaps location') parser.add_argument('--cpu-only', action='store_true', help='Force client to register as CPU only and also only reading out CPU information') + parser.add_argument('--max-log-size', default=5_000_000, type=int, required=False, help='Max size in bytes of client.log before rotation trigger; default 5000000 (5MB)') + parser.add_argument('--max-log-backups', default=5, type=int, required=False, help='Number of rotated client.log copies to keep; default 5.') args = parser.parse_args() if args.version: diff --git a/changelog.md b/changelog.md index 9f0db7f..cee4d45 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,12 @@ +## v0.7.2 -> v0.7.3 + +### Enhancements + +* Introduced rotating logfile for `client.log` with two new CLI flags for behavior. + ## v0.7.1 -> v0.7.2 ### Bugfixes -* When using older hashcat version Hashtopolis doesn't detect the binary correctly (hashcat64.bin) #hashtopolis/server/1012 +* When using older hashcat version Hashtopolis doesn't detect the binary correctly (hashcat64.bin) #hashtopolis/server/1012 ## v0.7.0 -> v0.7.1 diff --git a/htpclient/initialize.py b/htpclient/initialize.py index 8e1431c..f950b5d 100644 --- a/htpclient/initialize.py +++ b/htpclient/initialize.py @@ -16,7 +16,7 @@ def get_version(): @staticmethod def get_version_number(): - return "0.7.2" + return "0.7.3" def run(self, args): self.__check_cert(args) @@ -181,7 +181,7 @@ def __check_cert(self, args): cert = os.path.abspath(args.cert) logging.debug("Setting cert to: " + cert) self.config.set_value('cert', cert) - + if cert is not None: Session().s.cert = cert logging.debug("Configuration session cert to: " + cert) @@ -210,7 +210,7 @@ def __check_url(self, args): self.__check_url(args) else: logging.debug("Connection test successful!") - + if args.cpu_only is not None and args.cpu_only: logging.debug("Setting agent to be CPU only..") self.config.set_value('cpu-only', True) diff --git a/tests/test_hashcat_brain.py b/tests/test_hashcat_brain.py index ee2a741..c1895d6 100644 --- a/tests/test_hashcat_brain.py +++ b/tests/test_hashcat_brain.py @@ -43,20 +43,20 @@ class HashcatBrain(unittest.TestCase): def test_brain_linux(self, mock_system, mock_unlink, mock_check_output, mock_Popen): if sys.platform != 'linux': return - + # Setup session object session = Session(requests.Session()).s session.headers.update({'User-Agent': Initialize.get_version()}) # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Set config and variables cracker_id = 1 config = Config() crackers_path = config.get_value('crackers-path') - + # Setting Brain configuration set_config = { 'hashcatBrainEnable': '1', @@ -83,7 +83,7 @@ def test_brain_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop task_obj = Task_v2(**payload) task_obj.save() - # Try to download cracker 1 + # Try to download cracker 1 executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.bin') binaryDownload = BinaryDownload(test_args) @@ -159,7 +159,7 @@ def test_brain_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop '-a3 ?l?l?l?l ', ' --hash-type=0 ', ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( @@ -187,7 +187,7 @@ def test_brain_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop config_item = Config_v2.objects.get(item=k) config_item.value = v config_item.save() - + # Re-enable agents, because the the hashcat command will fail agent = Agent_v2.objects.get(token=config.get_value('token')) agent.isActive = True diff --git a/tests/test_hashcat_files.py b/tests/test_hashcat_files.py index 31bb5f8..eefdc33 100644 --- a/tests/test_hashcat_files.py +++ b/tests/test_hashcat_files.py @@ -46,7 +46,7 @@ def test_files_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop session.headers.update({'User-Agent': Initialize.get_version()}) # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Set config and variables cracker_id = 1 @@ -54,7 +54,7 @@ def test_files_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop crackers_path = config.get_value('crackers-path') files_path = config.get_value('files-path') - + # Create hashlist p = Path(__file__).parent.joinpath('create_hashlist_001.json') @@ -119,9 +119,9 @@ def test_files_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop if os.path.isfile(rule_path): os.remove(rule_path) - # Try to download cracker 1 + # Try to download cracker 1 executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.bin') - + binaryDownload = BinaryDownload(test_args) binaryDownload.check_version(cracker_id) @@ -202,7 +202,7 @@ def test_files_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop f'-a0 "{wordlist_path}" -r "{rule_path}" ', ' --hash-type=0 ', ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( @@ -226,4 +226,4 @@ def test_files_linux(self, mock_system, mock_unlink, mock_check_output, mock_Pop if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_hashcat_files_7z.py b/tests/test_hashcat_files_7z.py index 0e69a52..3237144 100644 --- a/tests/test_hashcat_files_7z.py +++ b/tests/test_hashcat_files_7z.py @@ -42,13 +42,13 @@ class HashcatFiles7z(unittest.TestCase): def test_files_7z_linux(self, mock_system, mock_unlink, mock_check_output, mock_Popen): if sys.platform != 'linux': return - + # Setup session object session = Session(requests.Session()).s session.headers.update({'User-Agent': Initialize.get_version()}) # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Set config and variables cracker_id = 1 @@ -67,10 +67,10 @@ def test_files_7z_linux(self, mock_system, mock_unlink, mock_check_output, mock_ stamp = datetime.datetime.now().isoformat() wordlist = f'wordlist-{stamp}.txt' sevenzip = f'wordlist-{stamp}.7z' - + with open(wordlist, 'w') as file_obj: file_obj.write('12345678\n123456\nprincess\n') - + with py7zr.SevenZipFile(sevenzip, 'w') as z: z.writeall(f'./{wordlist}') @@ -105,10 +105,10 @@ def test_files_7z_linux(self, mock_system, mock_unlink, mock_check_output, mock_ wordlist_path = Path(files_path, wordlist) if os.path.isfile(wordlist_path): os.remove(wordlist_path) - - # Try to download cracker 1 + + # Try to download cracker 1 executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.bin') - + binaryDownload = BinaryDownload(test_args) binaryDownload.check_version(cracker_id) @@ -192,7 +192,7 @@ def test_files_7z_linux(self, mock_system, mock_unlink, mock_check_output, mock_ f'-a0 "{wordlist_path}" ', ' --hash-type=0 ', ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( @@ -219,7 +219,7 @@ def test_files_7z_linux(self, mock_system, mock_unlink, mock_check_output, mock_ def test_files_7z_windows(self, mock_system, mock_unlink, mock_check_output, mock_Popen): if sys.platform != 'win32': return - + # Setup session object session = Session(requests.Session()).s session.headers.update({'User-Agent': Initialize.get_version()}) @@ -244,10 +244,10 @@ def test_files_7z_windows(self, mock_system, mock_unlink, mock_check_output, moc stamp = int(time.time()) wordlist = f'wordlist-{stamp}.txt' sevenzip = f'wordlist-{stamp}.7z' - + with open(wordlist, 'w') as file_obj: file_obj.write('12345678\n123456\nprincess\n') - + with py7zr.SevenZipFile(sevenzip, 'w') as z: z.writeall(f'./{wordlist}') @@ -282,10 +282,10 @@ def test_files_7z_windows(self, mock_system, mock_unlink, mock_check_output, moc wordlist_path = Path(files_path, wordlist) if os.path.isfile(wordlist_path): os.remove(wordlist_path) - - # Try to download cracker 1 + + # Try to download cracker 1 executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.exe') - + binaryDownload = BinaryDownload(test_args) binaryDownload.check_version(cracker_id) @@ -369,7 +369,7 @@ def test_files_7z_windows(self, mock_system, mock_unlink, mock_check_output, moc f'-a0 "{wordlist_path}" ', ' --hash-type=0 ', ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( @@ -385,4 +385,4 @@ def test_files_7z_windows(self, mock_system, mock_unlink, mock_check_output, moc hashlist_v2.delete() file_obj.delete() if os.path.isfile(wordlist_path): - os.remove(wordlist_path) \ No newline at end of file + os.remove(wordlist_path) diff --git a/tests/test_hashcat_preprocessor.py b/tests/test_hashcat_preprocessor.py index e09e06b..2797f93 100644 --- a/tests/test_hashcat_preprocessor.py +++ b/tests/test_hashcat_preprocessor.py @@ -40,7 +40,7 @@ class HashcatPreprocessor(unittest.TestCase): def test_preprocessor_linux(self, mock_system, mock_unlink, mock_check_output, mock_Popen): if sys.platform != 'linux': return - + # Setup session object session = Session(requests.Session()).s session.headers.update({'User-Agent': Initialize.get_version()}) @@ -63,17 +63,17 @@ def test_preprocessor_linux(self, mock_system, mock_unlink, mock_check_output, m shutil.rmtree(preprocessor_path) # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Try to download cracker 1 cracker_id = 1 config = Config() crackers_path = config.get_value('crackers-path') - + # executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.bin') - + binaryDownload = BinaryDownload(test_args) - + task = Task() task.load_task() @@ -173,7 +173,7 @@ def test_preprocessor_linux(self, mock_system, mock_unlink, mock_check_output, m def test_preprocessor_windows(self, mock_system, mock_unlink, mock_check_output, mock_Popen): if sys.platform != 'win32': return - + # Setup session object session = Session(requests.Session()).s session.headers.update({'User-Agent': Initialize.get_version()}) @@ -199,16 +199,16 @@ def test_preprocessor_windows(self, mock_system, mock_unlink, mock_check_output, shutil.rmtree(preprocessor_path) # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Try to download cracker 1 cracker_id = 1 crackers_path = config.get_value('crackers-path') - + # executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.bin') - + binaryDownload = BinaryDownload(test_args) - + task = Task() task.load_task() @@ -256,13 +256,13 @@ def test_preprocessor_windows(self, mock_system, mock_unlink, mock_check_output, '-o', f'"{hashlist_out_path}"' ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( full_cmd, shell=True, cwd=Path(crackers_path, str(cracker_id)), - stdout=-1, + stdout=-1, stderr=-2 ) diff --git a/tests/test_hashcat_runtime.py b/tests/test_hashcat_runtime.py index 52a2c6e..751fb8c 100644 --- a/tests/test_hashcat_runtime.py +++ b/tests/test_hashcat_runtime.py @@ -58,7 +58,7 @@ def test_runtime_windows(self, mock_check_output, moch_popen): obj.save() # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Try to download cracker 1 cracker_id = 1 @@ -96,7 +96,7 @@ def test_runtime_windows(self, mock_check_output, moch_popen): hashlist_out_path = Path(hashlists_path, f'{hashlist_id}.out') result = cracker.run_benchmark(task.get_task()) assert result != 0 - + full_cmd = [ '"hashcat.exe"', '--machine-readable', @@ -113,14 +113,14 @@ def test_runtime_windows(self, mock_check_output, moch_popen): '-o', f'"{hashlist_out_path}"' ] - + full_cmd = ' '.join(full_cmd) moch_popen.assert_called_with( full_cmd, shell=True, cwd=Path(crackers_path, str(cracker_id)), - stdout=-1, + stdout=-1, stderr=-1 ) diff --git a/tests/test_hashcat_simple.py b/tests/test_hashcat_simple.py index a1a40f4..6967e36 100644 --- a/tests/test_hashcat_simple.py +++ b/tests/test_hashcat_simple.py @@ -64,18 +64,18 @@ def test_simple_linux(self, mock_system, mock_unlink, mock_check_output, mock_Po obj.save() # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Try to download cracker 1 cracker_id = 1 config = Config() crackers_path = config.get_value('crackers-path') - + executeable_path = Path(crackers_path, str(cracker_id), 'hashcat.bin') - + binaryDownload = BinaryDownload(test_args) binaryDownload.check_version(cracker_id) - + cracker_zip = Path(crackers_path, f'{cracker_id}.7z') crackers_temp = Path(crackers_path, 'temp') zip_binary = './7zr' @@ -152,7 +152,7 @@ def test_simple_linux(self, mock_system, mock_unlink, mock_check_output, mock_Po '-a3 ?l?l?l?l ', ' --hash-type=0 ', ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( @@ -201,7 +201,7 @@ def test_simple_windows(self, mock_system, mock_unlink, mock_check_output, mock_ obj.save() # Cmd parameters setup - test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None) + test_args = Namespace( cert=None, cpu_only=False, crackers_path=None, de_register=False, debug=True, disable_update=False, files_path=None, hashlists_path=None, number_only=False, preprocessors_path=None, url='http://hashtopolis/api/server.php', version=False, voucher='devvoucher', zaps_path=None, max_log_size=5_000_000, max_log_backups=5) # Try to download cracker 1 cracker_id = 1 @@ -249,7 +249,7 @@ def test_simple_windows(self, mock_system, mock_unlink, mock_check_output, mock_ hashlist_out_path = Path(hashlists_path, f'{hashlist_id}.out') result = cracker.run_benchmark(task.get_task()) assert result != 0 - + full_cmd = [ '"hashcat.exe"', '--machine-readable', @@ -267,7 +267,7 @@ def test_simple_windows(self, mock_system, mock_unlink, mock_check_output, mock_ '-o', f'"{hashlist_out_path}"' ] - + full_cmd = ' '.join(full_cmd) mock_check_output.assert_called_with( @@ -314,7 +314,7 @@ def test_simple_windows(self, mock_system, mock_unlink, mock_check_output, mock_ '-a3 ?l?l?l?l ', ' --hash-type=0 ', ] - + full_cmd = ' '.join(full_cmd) mock_Popen.assert_called_with( @@ -330,4 +330,4 @@ def test_simple_windows(self, mock_system, mock_unlink, mock_check_output, mock_ hashlist_v2.delete() if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main()